summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorMarcel Ziswiler <marcel.ziswiler@toradex.com>2012-09-10 14:53:27 +0200
committerMarcel Ziswiler <marcel.ziswiler@toradex.com>2012-09-10 15:04:19 +0200
commitd5bbf34613a877dbe3da847fa0432da8c6721e73 (patch)
tree902a90fd7eda61aad7abae9c35b0da2e7a786995 /drivers
parentc6c1f7a2c194f1a2291a15c6691c0d6785f8976e (diff)
parent336961dd3cf9c39456dd9657e8f205718740c797 (diff)
Merge branch 'l4t/l4t-r16' into colibri
Merge with latest NVIDIA L4T R16. Only real conflict concerning inverted VBUS gpio support.
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/base/regmap/regmap-irq.c54
-rw-r--r--drivers/base/syscore.c8
-rw-r--r--drivers/bluetooth/bluesleep.c104
-rw-r--r--drivers/bluetooth/ti_bluesleep.c120
-rw-r--r--drivers/clk/clkdev.c45
-rw-r--r--drivers/cpufreq/cpufreq.c71
-rw-r--r--drivers/cpufreq/cpufreq_interactive.c90
-rw-r--r--drivers/cpufreq/cpufreq_stats.c1
-rw-r--r--drivers/cpuquiet/Kconfig11
-rw-r--r--drivers/cpuquiet/Makefile1
-rw-r--r--drivers/cpuquiet/cpuquiet.c32
-rw-r--r--drivers/cpuquiet/cpuquiet.h36
-rw-r--r--drivers/cpuquiet/cpuquiet_attribute.c133
-rw-r--r--drivers/cpuquiet/driver.c202
-rw-r--r--drivers/cpuquiet/governor.c102
-rw-r--r--drivers/cpuquiet/governors/Makefile1
-rw-r--r--drivers/cpuquiet/governors/balanced.c461
-rw-r--r--drivers/cpuquiet/governors/userspace.c56
-rw-r--r--drivers/cpuquiet/sysfs.c291
-rw-r--r--drivers/crypto/tegra-aes.c32
-rw-r--r--drivers/crypto/tegra-se.c27
-rw-r--r--drivers/gpio/Kconfig9
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/gpio-rc5t583.c180
-rw-r--r--drivers/gpio/gpio-tegra.c65
-rw-r--r--drivers/gpio/gpio-tps65910.c152
-rw-r--r--drivers/gpu/ion/tegra/Makefile2
-rw-r--r--drivers/gpu/ion/tegra/tegra_ion.c2
-rw-r--r--drivers/hwmon/tegra-tsensor.c588
-rw-r--r--drivers/i2c/busses/i2c-tegra.c28
-rw-r--r--drivers/input/misc/cm3217.c35
-rw-r--r--drivers/input/touchscreen/rmi4/rmi_driver.c4
-rw-r--r--drivers/input/touchscreen/rmi4/rmi_f01.c10
-rw-r--r--drivers/input/touchscreen/rmi4/rmi_f09.c20
-rw-r--r--drivers/input/touchscreen/rmi4/rmi_f11.c12
-rw-r--r--drivers/input/touchscreen/rmi4/rmi_f34.c10
-rw-r--r--drivers/input/touchscreen/rmi4/rmi_f54.c10
-rw-r--r--drivers/iommu/tegra-smmu.c15
-rw-r--r--drivers/media/video/tegra/Kconfig14
-rw-r--r--drivers/media/video/tegra/Makefile4
-rw-r--r--drivers/media/video/tegra/ad5816.c1188
-rw-r--r--drivers/media/video/tegra/ar0832_main.c55
-rw-r--r--drivers/media/video/tegra/avp/avp.c2
-rw-r--r--drivers/media/video/tegra/avp/avp_svc.c4
-rw-r--r--drivers/media/video/tegra/nvavp/Kconfig11
-rw-r--r--drivers/media/video/tegra/nvavp/Makefile2
-rw-r--r--drivers/media/video/tegra/nvavp/nvavp_dev.c624
-rw-r--r--drivers/media/video/tegra/ov2710.c162
-rw-r--r--drivers/media/video/tegra/ov5640.c493
-rw-r--r--drivers/media/video/tegra/ov5640_tables.h4582
-rw-r--r--drivers/media/video/tegra/ov5650.c101
-rw-r--r--drivers/media/video/tegra/sh532u.c243
-rw-r--r--drivers/media/video/tegra/tegra_camera.c36
-rw-r--r--drivers/media/video/tegra/tegra_dtv.c1
-rw-r--r--drivers/mfd/Kconfig11
-rw-r--r--drivers/mfd/Makefile2
-rw-r--r--drivers/mfd/max77663-core.c8
-rw-r--r--drivers/mfd/palmas.c509
-rw-r--r--drivers/mfd/rc5t583.c47
-rw-r--r--drivers/mfd/tps65910-irq.c34
-rw-r--r--drivers/mfd/tps65910.c218
-rw-r--r--drivers/mfd/tps80031.c38
-rw-r--r--drivers/misc/Kconfig7
-rw-r--r--drivers/misc/Makefile2
-rw-r--r--drivers/misc/bcm4329_rfkill.c15
-rw-r--r--drivers/misc/nct1008.c89
-rw-r--r--drivers/misc/tegra-baseband/Makefile2
-rw-r--r--drivers/misc/tegra-baseband/bb-m7400.c27
-rw-r--r--drivers/misc/tegra-cec/Kconfig19
-rw-r--r--drivers/misc/tegra-cec/Makefile5
-rw-r--r--drivers/misc/tegra-cec/tegra_cec.c383
-rw-r--r--drivers/misc/tegra-cec/tegra_cec.h134
-rw-r--r--drivers/misc/therm_est.c139
-rw-r--r--drivers/mmc/card/Kconfig10
-rw-r--r--drivers/mmc/card/block.c3
-rw-r--r--drivers/mmc/card/mmc_test.c2
-rw-r--r--drivers/mmc/core/core.c107
-rw-r--r--drivers/mmc/core/mmc.c19
-rw-r--r--drivers/mmc/core/mmc_ops.c65
-rw-r--r--drivers/mmc/core/mmc_ops.h1
-rw-r--r--drivers/mmc/host/sdhci-tegra.c68
-rw-r--r--drivers/mmc/host/sdhci.c20
-rw-r--r--drivers/mmc/host/sh_mmcif.c5
-rw-r--r--drivers/mmc/host/tmio_mmc_dma.c5
-rw-r--r--drivers/mtd/maps/tegra_nor.c4
-rw-r--r--drivers/net/usb/cdc_ether.c17
-rw-r--r--drivers/net/usb/smsc95xx.c16
-rw-r--r--drivers/net/wireless/bcmdhd/Kconfig28
-rw-r--r--drivers/net/wireless/bcmdhd/Makefile16
-rw-r--r--drivers/net/wireless/bcmdhd/aiutils.c2
-rw-r--r--drivers/net/wireless/bcmdhd/bcmevent.c8
-rw-r--r--drivers/net/wireless/bcmdhd/bcmsdh.c2
-rw-r--r--drivers/net/wireless/bcmdhd/bcmsdh_linux.c47
-rw-r--r--drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c231
-rw-r--r--drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c60
-rw-r--r--drivers/net/wireless/bcmdhd/bcmutils.c4
-rw-r--r--drivers/net/wireless/bcmdhd/dhd.h71
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_cdc.c18
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_cfg80211.c655
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_cfg80211.h45
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_common.c54
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_dbg.h4
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_linux.c742
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_linux_mon.c38
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_proto.h2
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_sdio.c108
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_wlfc.h12
-rw-r--r--drivers/net/wireless/bcmdhd/hndpmu.c28
-rw-r--r--drivers/net/wireless/bcmdhd/include/Makefile2
-rw-r--r--drivers/net/wireless/bcmdhd/include/aidmp.h2
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmcdc.h2
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmdefs.h37
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmdevs.h572
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmendian.h2
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmpcispi.h2
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmperf.h2
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmsdbus.h10
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmsdh.h10
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h9
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmsdpcm.h2
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmsdspi.h2
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmsdstd.h37
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmspi.h2
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmutils.h14
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmwifi.h2
-rw-r--r--drivers/net/wireless/bcmdhd/include/dhdioctl.h4
-rw-r--r--drivers/net/wireless/bcmdhd/include/epivers.h15
-rw-r--r--drivers/net/wireless/bcmdhd/include/hndpmu.h2
-rw-r--r--drivers/net/wireless/bcmdhd/include/hndrte_armtrap.h2
-rw-r--r--drivers/net/wireless/bcmdhd/include/hndrte_cons.h2
-rw-r--r--drivers/net/wireless/bcmdhd/include/hndsoc.h2
-rw-r--r--drivers/net/wireless/bcmdhd/include/htsf.h2
-rw-r--r--drivers/net/wireless/bcmdhd/include/linux_osl.h4
-rw-r--r--drivers/net/wireless/bcmdhd/include/linuxver.h23
-rw-r--r--drivers/net/wireless/bcmdhd/include/miniopt.h2
-rw-r--r--drivers/net/wireless/bcmdhd/include/msgtrace.h2
-rw-r--r--drivers/net/wireless/bcmdhd/include/osl.h2
-rw-r--r--drivers/net/wireless/bcmdhd/include/packed_section_end.h2
-rw-r--r--drivers/net/wireless/bcmdhd/include/packed_section_start.h2
-rw-r--r--drivers/net/wireless/bcmdhd/include/pcicfg.h28
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/802.11.h327
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/802.11_bta.h2
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/802.11e.h2
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/802.1d.h2
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/bcmeth.h2
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/bcmevent.h9
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/bcmip.h2
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/bt_amp_hci.h2
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/eapol.h2
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/ethernet.h3
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/p2p.h2
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/sdspi.h2
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/vlan.h2
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/wpa.h12
-rw-r--r--drivers/net/wireless/bcmdhd/include/sbchipc.h171
-rw-r--r--drivers/net/wireless/bcmdhd/include/sbconfig.h2
-rw-r--r--drivers/net/wireless/bcmdhd/include/sbhnddma.h6
-rw-r--r--drivers/net/wireless/bcmdhd/include/sbpcmcia.h2
-rw-r--r--drivers/net/wireless/bcmdhd/include/sbsdio.h2
-rw-r--r--drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h2
-rw-r--r--drivers/net/wireless/bcmdhd/include/sbsocram.h2
-rw-r--r--drivers/net/wireless/bcmdhd/include/sdio.h5
-rw-r--r--drivers/net/wireless/bcmdhd/include/sdioh.h32
-rw-r--r--drivers/net/wireless/bcmdhd/include/sdiovar.h2
-rw-r--r--drivers/net/wireless/bcmdhd/include/siutils.h30
-rw-r--r--drivers/net/wireless/bcmdhd/include/trxhdr.h3
-rw-r--r--drivers/net/wireless/bcmdhd/include/typedefs.h5
-rw-r--r--drivers/net/wireless/bcmdhd/include/wlfc_proto.h2
-rw-r--r--drivers/net/wireless/bcmdhd/include/wlioctl.h104
-rw-r--r--drivers/net/wireless/bcmdhd/linux_osl.c33
-rw-r--r--drivers/net/wireless/bcmdhd/siutils.c203
-rw-r--r--drivers/net/wireless/bcmdhd/wl_android.c88
-rw-r--r--drivers/net/wireless/bcmdhd/wl_android.h2
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfg80211.c3698
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfg80211.h404
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfgp2p.c650
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfgp2p.h54
-rw-r--r--drivers/net/wireless/bcmdhd/wl_iw.c156
-rw-r--r--drivers/net/wireless/bcmdhd/wl_iw.h25
-rw-r--r--drivers/net/wireless/bcmdhd/wl_linux_mon.c409
-rw-r--r--drivers/net/wireless/bcmdhd/wldev_common.c119
-rw-r--r--drivers/net/wireless/bcmdhd/wldev_common.h24
-rw-r--r--drivers/net/wireless/sd8797/Makefile1
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_11d.c3
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_11h.c42
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_11n.c9
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_11n_aggr.c5
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_11n_rxreorder.c5
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_cfp.c368
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_cmdevt.c29
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_decl.h18
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_fw.h46
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_ieee.h4
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_init.c13
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_ioctl.h69
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_main.h95
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_misc.c93
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_scan.c84
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_sdio.c4
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_shim.c7
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_sta_cmd.c116
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_sta_cmdresp.c94
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_sta_event.c10
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_sta_ioctl.c264
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_sta_rx.c4
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_sta_tx.c5
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_txrx.c10
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_uap_cmdevent.c2
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_uap_ioctl.c6
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_uap_txrx.c2
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_wmm.c55
-rw-r--r--drivers/net/wireless/sd8797/mlinux/mlan.h35
-rw-r--r--drivers/net/wireless/sd8797/mlinux/mlan_decl.h893
-rw-r--r--drivers/net/wireless/sd8797/mlinux/mlan_ieee.h1322
-rw-r--r--drivers/net/wireless/sd8797/mlinux/mlan_ioctl.h2981
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_cfg80211.c630
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_cfg80211.h16
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.c1058
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.h23
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_ioctl.c272
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_main.c323
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_main.h74
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_priv.c188
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_priv.h14
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_proc.c6
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_sdio_mmc.c6
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_shim.c83
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.c360
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_uap_cfg80211.c482
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_wext.c17
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_wext.h1
-rw-r--r--drivers/pci/pcie/Kconfig25
-rw-r--r--drivers/pci/pcie/aspm.c8
-rw-r--r--drivers/power/bq27x00_battery.c6
-rw-r--r--drivers/power/smb349-charger.c252
-rw-r--r--drivers/regulator/Kconfig29
-rw-r--r--drivers/regulator/Makefile3
-rw-r--r--drivers/regulator/max77663-regulator.c2
-rw-r--r--drivers/regulator/max8973-regulator.c606
-rw-r--r--drivers/regulator/rc5t583-regulator.c363
-rw-r--r--drivers/regulator/tps62360-regulator.c286
-rw-r--r--drivers/regulator/tps6238x0-regulator.c470
-rw-r--r--drivers/regulator/tps65910-regulator.c88
-rw-r--r--drivers/regulator/tps80031-regulator.c9
-rw-r--r--drivers/rtc/rtc-max77663.c24
-rw-r--r--drivers/rtc/rtc-tps6591x.c8
-rw-r--r--drivers/rtc/rtc-tps80031.c49
-rw-r--r--drivers/spi/spi-tegra.c521
-rw-r--r--drivers/spi/spi-topcliff-pch.c5
-rw-r--r--drivers/staging/iio/light/ltr558als.c16
-rw-r--r--drivers/tty/serial/amba-pl011.c5
-rw-r--r--drivers/tty/serial/pch_uart.c5
-rw-r--r--drivers/tty/serial/sh-sci.c5
-rw-r--r--drivers/tty/serial/tegra_hsuart.c33
-rw-r--r--drivers/usb/gadget/Kconfig11
-rw-r--r--drivers/usb/gadget/Makefile5
-rw-r--r--drivers/usb/gadget/android.c8
-rw-r--r--drivers/usb/gadget/fsl_tegra_udc.c170
-rw-r--r--drivers/usb/gadget/gadget_chips.h4
-rw-r--r--drivers/usb/gadget/tegra_udc.c2790
-rw-r--r--drivers/usb/gadget/tegra_udc.h440
-rw-r--r--drivers/usb/host/ehci-hub.c12
-rw-r--r--drivers/usb/host/ehci-tegra.c1375
-rw-r--r--drivers/usb/host/ehci.h1
-rw-r--r--drivers/usb/otg/tegra-otg.c274
-rw-r--r--drivers/usb/serial/baseband_usb_chr.c84
-rw-r--r--drivers/video/backlight/tegra_pwm_bl.c12
-rw-r--r--drivers/video/mx3fb.c5
-rw-r--r--drivers/video/tegra/Kconfig47
-rw-r--r--drivers/video/tegra/Makefile2
-rw-r--r--drivers/video/tegra/dc/Makefile4
-rw-r--r--drivers/video/tegra/dc/bandwidth.c284
-rw-r--r--drivers/video/tegra/dc/clock.c150
-rw-r--r--drivers/video/tegra/dc/csc.c67
-rw-r--r--drivers/video/tegra/dc/dc.c1730
-rw-r--r--drivers/video/tegra/dc/dc_config.c247
-rw-r--r--drivers/video/tegra/dc/dc_config.h162
-rw-r--r--drivers/video/tegra/dc/dc_priv.h190
-rw-r--r--drivers/video/tegra/dc/dc_reg.h11
-rw-r--r--drivers/video/tegra/dc/dc_sysfs.c2
-rw-r--r--drivers/video/tegra/dc/dsi.c360
-rw-r--r--drivers/video/tegra/dc/dsi.h28
-rw-r--r--drivers/video/tegra/dc/dsi_regs.h28
-rw-r--r--drivers/video/tegra/dc/edid.c2
-rw-r--r--drivers/video/tegra/dc/ext/Makefile2
-rw-r--r--drivers/video/tegra/dc/ext/control.c9
-rw-r--r--drivers/video/tegra/dc/ext/cursor.c2
-rw-r--r--drivers/video/tegra/dc/ext/dev.c80
-rw-r--r--drivers/video/tegra/dc/ext/events.c2
-rw-r--r--drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h4
-rw-r--r--drivers/video/tegra/dc/ext/util.c4
-rw-r--r--drivers/video/tegra/dc/hdmi.c56
-rw-r--r--drivers/video/tegra/dc/hdmi.h2
-rw-r--r--drivers/video/tegra/dc/hdmi_reg.h2
-rw-r--r--drivers/video/tegra/dc/lut.c130
-rw-r--r--drivers/video/tegra/dc/mode.c318
-rw-r--r--drivers/video/tegra/dc/nvhdcp.c2
-rw-r--r--drivers/video/tegra/dc/nvhdcp.h2
-rw-r--r--drivers/video/tegra/dc/nvsd.c7
-rw-r--r--drivers/video/tegra/dc/nvsd.h2
-rw-r--r--drivers/video/tegra/dc/rgb.c6
-rw-r--r--drivers/video/tegra/dc/window.c466
-rw-r--r--drivers/video/tegra/fb.c162
-rw-r--r--drivers/video/tegra/host/Makefile9
-rw-r--r--drivers/video/tegra/host/bus.c100
-rw-r--r--drivers/video/tegra/host/bus.h38
-rw-r--r--drivers/video/tegra/host/bus_client.c195
-rw-r--r--drivers/video/tegra/host/bus_client.h4
-rw-r--r--drivers/video/tegra/host/chip_support.c56
-rw-r--r--drivers/video/tegra/host/chip_support.h247
-rw-r--r--drivers/video/tegra/host/debug.c89
-rw-r--r--drivers/video/tegra/host/dev.c557
-rw-r--r--drivers/video/tegra/host/dev.h52
-rw-r--r--drivers/video/tegra/host/dsi/Makefile7
-rw-r--r--drivers/video/tegra/host/dsi/dsi.c82
-rw-r--r--drivers/video/tegra/host/gr2d/gr2d.c17
-rw-r--r--drivers/video/tegra/host/gr3d/gr3d.c130
-rw-r--r--drivers/video/tegra/host/gr3d/gr3d_t20.c56
-rw-r--r--drivers/video/tegra/host/gr3d/gr3d_t20.h3
-rw-r--r--drivers/video/tegra/host/gr3d/gr3d_t30.c113
-rw-r--r--drivers/video/tegra/host/gr3d/gr3d_t30.h3
-rw-r--r--drivers/video/tegra/host/host1x/Makefile6
-rw-r--r--drivers/video/tegra/host/host1x/host1x.c537
-rw-r--r--drivers/video/tegra/host/host1x/host1x.h78
-rw-r--r--drivers/video/tegra/host/host1x/host1x01_hardware.h170
-rw-r--r--drivers/video/tegra/host/host1x/host1x_cdma.c347
-rw-r--r--drivers/video/tegra/host/host1x/host1x_cdma.h4
-rw-r--r--drivers/video/tegra/host/host1x/host1x_channel.c168
-rw-r--r--drivers/video/tegra/host/host1x/host1x_channel.h45
-rw-r--r--drivers/video/tegra/host/host1x/host1x_debug.c233
-rw-r--r--drivers/video/tegra/host/host1x/host1x_hardware.h274
-rw-r--r--drivers/video/tegra/host/host1x/host1x_hwctx.h5
-rw-r--r--drivers/video/tegra/host/host1x/host1x_intr.c171
-rw-r--r--drivers/video/tegra/host/host1x/host1x_syncpt.c154
-rw-r--r--drivers/video/tegra/host/host1x/host1x_syncpt.h27
-rw-r--r--drivers/video/tegra/host/host1x/hw_host1x01_channel.h182
-rw-r--r--drivers/video/tegra/host/host1x/hw_host1x01_sync.h398
-rw-r--r--drivers/video/tegra/host/host1x/hw_host1x01_uclass.h474
-rw-r--r--drivers/video/tegra/host/isp/isp.c30
-rw-r--r--drivers/video/tegra/host/mpe/mpe.c160
-rw-r--r--drivers/video/tegra/host/nvhost_acm.c229
-rw-r--r--drivers/video/tegra/host/nvhost_acm.h2
-rw-r--r--drivers/video/tegra/host/nvhost_cdma.c195
-rw-r--r--drivers/video/tegra/host/nvhost_cdma.h38
-rw-r--r--drivers/video/tegra/host/nvhost_channel.c90
-rw-r--r--drivers/video/tegra/host/nvhost_channel.h47
-rw-r--r--drivers/video/tegra/host/nvhost_hwctx.h1
-rw-r--r--drivers/video/tegra/host/nvhost_intr.c69
-rw-r--r--drivers/video/tegra/host/nvhost_intr.h2
-rw-r--r--drivers/video/tegra/host/nvhost_job.c358
-rw-r--r--drivers/video/tegra/host/nvhost_job.h42
-rw-r--r--drivers/video/tegra/host/nvhost_memmgr.c34
-rw-r--r--drivers/video/tegra/host/nvhost_memmgr.h38
-rw-r--r--drivers/video/tegra/host/nvhost_syncpt.c161
-rw-r--r--drivers/video/tegra/host/nvhost_syncpt.h45
-rw-r--r--drivers/video/tegra/host/nvmap.c100
-rw-r--r--drivers/video/tegra/host/nvmap.h27
-rw-r--r--drivers/video/tegra/host/t20/t20.c265
-rw-r--r--drivers/video/tegra/host/t20/t20.h10
-rw-r--r--drivers/video/tegra/host/t30/t30.c287
-rw-r--r--drivers/video/tegra/host/t30/t30.h6
-rw-r--r--drivers/video/tegra/host/vi/vi.c30
-rw-r--r--drivers/video/tegra/nvmap/Makefile1
-rw-r--r--drivers/video/tegra/nvmap/nvmap.c270
-rw-r--r--drivers/video/tegra/nvmap/nvmap.h96
-rw-r--r--drivers/video/tegra/nvmap/nvmap_dev.c34
-rw-r--r--drivers/video/tegra/nvmap/nvmap_handle.c115
-rw-r--r--drivers/video/tegra/nvmap/nvmap_heap.c2
-rw-r--r--drivers/video/tegra/nvmap/nvmap_ioctl.c12
-rw-r--r--drivers/video/tegra/nvmap/nvmap_ioctl.h2
-rw-r--r--drivers/video/tegra/nvmap/nvmap_iommu.c97
-rw-r--r--drivers/watchdog/tegra_wdt.c201
373 files changed, 41048 insertions, 12066 deletions
diff --git a/drivers/Makefile b/drivers/Makefile
index 4cbb7ce0a0f9..d7f4b63904ac 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -5,6 +5,7 @@
# Rewritten to use lists instead of if-statements.
#
+obj-$(CONFIG_CPUQUIET_FRAMEWORK)+= cpuquiet/
obj-y += gpio/
obj-$(CONFIG_PCI) += pci/
obj-$(CONFIG_PARISC) += parisc/
diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c
index cc7b4f764d63..2691907757c4 100644
--- a/drivers/base/regmap/regmap-irq.c
+++ b/drivers/base/regmap/regmap-irq.c
@@ -26,10 +26,11 @@ struct regmap_irq_chip_data {
int irq_base;
- void *status_reg_buf;
unsigned int *status_buf;
unsigned int *mask_buf;
unsigned int *mask_buf_def;
+
+ unsigned int irq_reg_stride;
};
static inline const
@@ -59,7 +60,8 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
*/
for (i = 0; i < d->chip->num_regs; i++) {
ret = regmap_update_bits(d->map, d->chip->mask_base +
- (i * map->reg_stride),
+ (i * map->reg_stride *
+ d->irq_reg_stride),
d->mask_buf_def[i], d->mask_buf[i]);
if (ret != 0)
dev_err(d->map->dev, "Failed to sync masks in %x\n",
@@ -101,18 +103,8 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
struct regmap_irq_chip *chip = data->chip;
struct regmap *map = data->map;
int ret, i;
- u8 *buf8 = data->status_reg_buf;
- u16 *buf16 = data->status_reg_buf;
- u32 *buf32 = data->status_reg_buf;
bool handled = false;
- ret = regmap_bulk_read(map, chip->status_base, data->status_reg_buf,
- chip->num_regs);
- if (ret != 0) {
- dev_err(map->dev, "Failed to read IRQ status: %d\n", ret);
- return IRQ_NONE;
- }
-
/*
* Ignore masked IRQs and ack if we need to; we ack early so
* there is no race between handling and acknowleding the
@@ -121,18 +113,13 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
* doing a write per register.
*/
for (i = 0; i < data->chip->num_regs; i++) {
- switch (map->format.val_bytes) {
- case 1:
- data->status_buf[i] = buf8[i];
- break;
- case 2:
- data->status_buf[i] = buf16[i];
- break;
- case 4:
- data->status_buf[i] = buf32[i];
- break;
- default:
- BUG();
+ ret = regmap_read(map, chip->mask_base + (i * map->reg_stride
+ * data->irq_reg_stride),
+ &data->status_buf[i]);
+
+ if (ret != 0) {
+ dev_err(map->dev, "Failed to read IRQ status: %d\n",
+ ret);
return IRQ_NONE;
}
@@ -140,7 +127,8 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
if (data->status_buf[i] && chip->ack_base) {
ret = regmap_write(map, chip->ack_base +
- (i * map->reg_stride),
+ (i * map->reg_stride *
+ data->irq_reg_stride),
data->status_buf[i]);
if (ret != 0)
dev_err(map->dev, "Failed to ack 0x%x: %d\n",
@@ -210,11 +198,6 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
if (!d->status_buf)
goto err_alloc;
- d->status_reg_buf = kzalloc(map->format.val_bytes * chip->num_regs,
- GFP_KERNEL);
- if (!d->status_reg_buf)
- goto err_alloc;
-
d->mask_buf = kzalloc(sizeof(unsigned int) * chip->num_regs,
GFP_KERNEL);
if (!d->mask_buf)
@@ -228,6 +211,12 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
d->map = map;
d->chip = chip;
d->irq_base = irq_base;
+
+ if (chip->irq_reg_stride)
+ d->irq_reg_stride = chip->irq_reg_stride;
+ else
+ d->irq_reg_stride = 1;
+
mutex_init(&d->lock);
for (i = 0; i < chip->num_irqs; i++)
@@ -237,7 +226,8 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
/* Mask all the interrupts by default */
for (i = 0; i < chip->num_regs; i++) {
d->mask_buf[i] = d->mask_buf_def[i];
- ret = regmap_write(map, chip->mask_base + (i * map->reg_stride),
+ ret = regmap_write(map, chip->mask_base + (i * map->reg_stride
+ * d->irq_reg_stride),
d->mask_buf[i]);
if (ret != 0) {
dev_err(map->dev, "Failed to set masks in 0x%x: %d\n",
@@ -276,7 +266,6 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
err_alloc:
kfree(d->mask_buf_def);
kfree(d->mask_buf);
- kfree(d->status_reg_buf);
kfree(d->status_buf);
kfree(d);
return ret;
@@ -297,7 +286,6 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
free_irq(irq, d);
kfree(d->mask_buf_def);
kfree(d->mask_buf);
- kfree(d->status_reg_buf);
kfree(d->status_buf);
kfree(d);
}
diff --git a/drivers/base/syscore.c b/drivers/base/syscore.c
index e8d11b6630ee..0240f01714a1 100644
--- a/drivers/base/syscore.c
+++ b/drivers/base/syscore.c
@@ -97,12 +97,16 @@ void syscore_resume(void)
list_for_each_entry(ops, &syscore_ops_list, node)
if (ops->resume) {
- if (initcall_debug)
- pr_info("PM: Calling %pF\n", ops->resume);
ops->resume();
WARN_ONCE(!irqs_disabled(),
"Interrupts enabled after %pF\n", ops->resume);
}
+ if (initcall_debug) {
+ list_for_each_entry(ops, &syscore_ops_list, node)
+ if (ops->resume) {
+ pr_info("PM: Called %pF\n", ops->resume);
+ }
+ }
}
EXPORT_SYMBOL_GPL(syscore_resume);
#endif /* CONFIG_PM_SLEEP */
diff --git a/drivers/bluetooth/bluesleep.c b/drivers/bluetooth/bluesleep.c
index 0e2ec0befbe3..910e510e0b7e 100644
--- a/drivers/bluetooth/bluesleep.c
+++ b/drivers/bluetooth/bluesleep.c
@@ -277,13 +277,28 @@ static int bluesleep_hci_event(struct notifier_block *this,
case HCI_DEV_REG:
if (!bluesleep_hdev) {
bluesleep_hdev = hdev;
- hu = (struct hci_uart *) hdev->driver_data;
- state = (struct uart_state *) hu->tty->driver_data;
- bsi->uport = state->uart_port;
+ if (bsi->has_ext_wake == 1) {
+ hu = (struct hci_uart *) hdev->driver_data;
+ state = (struct uart_state *) \
+ hu->tty->driver_data;
+ bsi->uport = state->uart_port;
+ }
/* if bluetooth started, start bluesleep*/
bluesleep_start();
}
break;
+ case HCI_DEV_UP:
+#if BT_ENABLE_IRQ_WAKE
+ if (enable_irq_wake(bsi->host_wake_irq))
+ BT_ERR("Couldn't enable BT_HOST_WAKE as wakeup interrupt");
+#endif
+ break;
+ case HCI_DEV_DOWN:
+#if BT_ENABLE_IRQ_WAKE
+ if (disable_irq_wake(bsi->host_wake_irq))
+ BT_ERR("Couldn't disable hostwake IRQ wakeup mode\n");
+#endif
+ break;
case HCI_DEV_UNREG:
bluesleep_stop();
bluesleep_hdev = NULL;
@@ -291,7 +306,8 @@ static int bluesleep_hci_event(struct notifier_block *this,
/* if bluetooth stopped, stop bluesleep also */
break;
case HCI_DEV_WRITE:
- bluesleep_outgoing_data();
+ if (bsi->has_ext_wake == 1)
+ bluesleep_outgoing_data();
break;
}
@@ -337,7 +353,8 @@ static void bluesleep_tx_timer_expire(unsigned long data)
static irqreturn_t bluesleep_hostwake_isr(int irq, void *dev_id)
{
/* schedule a tasklet to handle the change in the host wake line */
- tasklet_schedule(&hostwake_task);
+ if (bsi->has_ext_wake == 1)
+ tasklet_schedule(&hostwake_task);
return IRQ_HANDLED;
}
@@ -348,7 +365,6 @@ static irqreturn_t bluesleep_hostwake_isr(int irq, void *dev_id)
*/
static int bluesleep_start(void)
{
- int retval;
unsigned long irq_flags;
spin_lock_irqsave(&rw_lock, irq_flags);
@@ -363,28 +379,23 @@ static int bluesleep_start(void)
return -EBUSY;
}
- /* start the timer */
- mod_timer(&tx_timer, jiffies + (TX_TIMER_INTERVAL * HZ));
-
/* assert BT_WAKE */
- if (bsi->has_ext_wake == 1)
+ if (bsi->has_ext_wake == 1) {
+ /* start the timer */
+ mod_timer(&tx_timer, jiffies + (TX_TIMER_INTERVAL * HZ));
gpio_set_value(bsi->ext_wake, 1);
- set_bit(BT_EXT_WAKE, &flags);
-#if BT_ENABLE_IRQ_WAKE
- retval = enable_irq_wake(bsi->host_wake_irq);
- if (retval < 0) {
- BT_ERR("Couldn't enable BT_HOST_WAKE as wakeup interrupt");
- goto fail;
+ wake_lock(&bsi->wake_lock);
+ set_bit(BT_EXT_WAKE, &flags);
}
-#endif
+
set_bit(BT_PROTO, &flags);
- wake_lock(&bsi->wake_lock);
return 0;
fail:
- del_timer(&tx_timer);
+ if (bsi->has_ext_wake == 1)
+ del_timer(&tx_timer);
atomic_inc(&open_count);
- return retval;
+ return 0;
}
/**
@@ -400,25 +411,20 @@ static void bluesleep_stop(void)
return;
}
/* assert BT_WAKE */
- if (bsi->has_ext_wake == 1)
+ if (bsi->has_ext_wake == 1) {
gpio_set_value(bsi->ext_wake, 1);
- set_bit(BT_EXT_WAKE, &flags);
- del_timer(&tx_timer);
- clear_bit(BT_PROTO, &flags);
-
- if (test_bit(BT_ASLEEP, &flags)) {
- clear_bit(BT_ASLEEP, &flags);
- hsuart_power(1);
+ set_bit(BT_EXT_WAKE, &flags);
+ del_timer(&tx_timer);
+ wake_lock_timeout(&bsi->wake_lock, HZ / 2);
+ if (test_bit(BT_ASLEEP, &flags)) {
+ clear_bit(BT_ASLEEP, &flags);
+ hsuart_power(1);
+ }
}
+ clear_bit(BT_PROTO, &flags);
atomic_inc(&open_count);
spin_unlock_irqrestore(&rw_lock, irq_flags);
-
-#if BT_ENABLE_IRQ_WAKE
- if (disable_irq_wake(bsi->host_wake_irq))
- BT_ERR("Couldn't disable hostwake IRQ wakeup mode\n");
-#endif
- wake_lock_timeout(&bsi->wake_lock, HZ / 2);
}
/**
* Read the <code>BT_WAKE</code> GPIO pin value via the proc interface.
@@ -796,18 +802,19 @@ static int __init bluesleep_init(void)
/* Initialize spinlock. */
spin_lock_init(&rw_lock);
- /* Initialize timer */
- init_timer(&tx_timer);
- tx_timer.function = bluesleep_tx_timer_expire;
- tx_timer.data = 0;
+ /* assert bt wake */
+ if (bsi->has_ext_wake == 1) {
+ /* Initialize timer */
+ init_timer(&tx_timer);
+ tx_timer.function = bluesleep_tx_timer_expire;
+ tx_timer.data = 0;
- /* initialize host wake tasklet */
- tasklet_init(&hostwake_task, bluesleep_hostwake_task, 0);
+ /* initialize host wake tasklet */
+ tasklet_init(&hostwake_task, bluesleep_hostwake_task, 0);
- /* assert bt wake */
- if (bsi->has_ext_wake == 1)
gpio_set_value(bsi->ext_wake, 1);
- set_bit(BT_EXT_WAKE, &flags);
+ set_bit(BT_EXT_WAKE, &flags);
+ }
hci_register_notifier(&hci_event_nblock);
return 0;
@@ -831,16 +838,17 @@ static void __exit bluesleep_exit(void)
return;
/* assert bt wake */
- if (bsi->has_ext_wake == 1)
+ if (bsi->has_ext_wake == 1) {
gpio_set_value(bsi->ext_wake, 1);
- set_bit(BT_EXT_WAKE, &flags);
+ del_timer(&tx_timer);
+ if (test_bit(BT_ASLEEP, &flags))
+ hsuart_power(1);
+ set_bit(BT_EXT_WAKE, &flags);
+ }
if (test_bit(BT_PROTO, &flags)) {
if (disable_irq_wake(bsi->host_wake_irq))
BT_ERR("Couldn't disable hostwake IRQ wakeup mode\n");
free_irq(bsi->host_wake_irq, NULL);
- del_timer(&tx_timer);
- if (test_bit(BT_ASLEEP, &flags))
- hsuart_power(1);
}
hci_unregister_notifier(&hci_event_nblock);
diff --git a/drivers/bluetooth/ti_bluesleep.c b/drivers/bluetooth/ti_bluesleep.c
index d86fd261e676..2ab532410c72 100644
--- a/drivers/bluetooth/ti_bluesleep.c
+++ b/drivers/bluetooth/ti_bluesleep.c
@@ -31,37 +31,17 @@
*/
#include <linux/module.h> /* kernel module definitions */
-#include <linux/errno.h>
#include <linux/init.h>
#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/notifier.h>
-#include <linux/proc_fs.h>
-#include <linux/spinlock.h>
-#include <linux/timer.h>
-#include <linux/uaccess.h>
-#include <linux/version.h>
-#include <linux/workqueue.h>
#include <linux/platform_device.h>
-#include <linux/irq.h>
-#include <linux/ioport.h>
-#include <linux/param.h>
-#include <linux/bitops.h>
-#include <linux/termios.h>
-#include <linux/wakelock.h>
#include <mach/gpio.h>
-#include <linux/serial_core.h>
-#include <linux/tegra_uart.h>
#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h> /* event notifications */
-#include "hci_uart.h"
/*
* Defines
*/
-
#define VERSION "1.1"
#define POLARITY_LOW 0
@@ -70,9 +50,7 @@
struct bluesleep_info {
unsigned host_wake_irq;
struct uart_port *uport;
- struct wake_lock wake_lock;
int irq_polarity;
- int has_ext_wake;
};
@@ -81,16 +59,6 @@ struct bluesleep_info {
#define BT_ACTIVE 0x02
#define BT_SUSPEND 0x04
-
-/* work function */
-static void hostwake_sleep_work(struct work_struct *work);
-
-/* work queue */
-DECLARE_DELAYED_WORK(ti_sleep_workqueue, hostwake_sleep_work);
-
-/* Macros for handling sleep work */
-#define hostwake_workqueue() schedule_delayed_work(&ti_sleep_workqueue, 0)
-
static struct bluesleep_info *bsi;
/* module usage */
@@ -102,66 +70,6 @@ static atomic_t open_count = ATOMIC_INIT(1);
/** Global state flags */
static unsigned long flags;
-/** Tasklet to respond to change in hostwake line */
-static struct tasklet_struct hostwake_task;
-
-/** Lock for state transitions */
-static spinlock_t rw_lock;
-
-/*
- * Local functions
- */
-static void hsuart_power(int on)
-{
- pr_debug("%s", __func__);
-
- if (on) {
- tegra_uart_request_clock_on(bsi->uport);
- tegra_uart_set_mctrl(bsi->uport, TIOCM_RTS);
- } else {
- tegra_uart_set_mctrl(bsi->uport, 0);
- tegra_uart_request_clock_off(bsi->uport);
- }
-}
-
-
-
-/**
- * @brief@ main sleep work handling function which update the flags
- * and activate and deactivate UART .
- */
-
-static void hostwake_sleep_work(struct work_struct *work)
-{
- pr_debug("%s", __func__);
- free_irq(bsi->host_wake_irq, "tibluesleep");
- /*Activating UART */
- if (test_bit(BT_SUSPEND, &flags)) {
- BT_DBG("Activate UART");
- hsuart_power(1);
-
- }
- bsi->has_ext_wake = 0;
- clear_bit(BT_SUSPEND, &flags);
- set_bit(BT_ACTIVE, &flags);
-
-}
-
-
-/**
- * A tasklet function that runs in tasklet context
- * @param data Not used.
- */
-static void bluesleep_hostwake_task(unsigned long data)
-{
- pr_debug("%s", __func__);
- disable_irq(bsi->host_wake_irq);
- spin_lock(&rw_lock);
- hostwake_workqueue();
- spin_unlock(&rw_lock);
-}
-
-
/**
* Schedules a tasklet to run when receiving an interrupt on the
* <code>HOST_WAKE</code> GPIO pin.
@@ -170,11 +78,8 @@ static void bluesleep_hostwake_task(unsigned long data)
*/
static irqreturn_t bluesleep_hostwake_isr(int irq, void *dev_id)
{
-
pr_debug("%s", __func__);
- /* schedule a tasklet to handle the change in the host wake line */
- bsi->has_ext_wake = 1;
- tasklet_schedule(&hostwake_task);
+ disable_irq_nosync(bsi->host_wake_irq);
return IRQ_HANDLED;
}
@@ -183,8 +88,7 @@ static irqreturn_t bluesleep_hostwake_isr(int irq, void *dev_id)
* @return On success, 0. On error, -1, and <code>errno</code> is set
* appropriately.
*/
-
- int bluesleep_start(struct uart_port *uport)
+int bluesleep_start(struct uart_port *uport)
{
int retval;
bsi->uport = uport;
@@ -224,9 +128,8 @@ fail:
/**
* Stops the Sleep-Mode Protocol on the Host.
*/
- void bluesleep_stop(void)
+void bluesleep_stop(void)
{
-
pr_debug("%s", __func__);
if (disable_irq_wake(bsi->host_wake_irq))
@@ -264,7 +167,6 @@ static int bluesleep_probe(struct platform_device *pdev)
else
bsi->irq_polarity = POLARITY_HIGH;/*anything else*/
- wake_lock_init(&bsi->wake_lock, WAKE_LOCK_SUSPEND, "bluesleep");
clear_bit(BT_SUSPEND, &flags);
set_bit(BT_ACTIVE, &flags);
@@ -282,17 +184,11 @@ static int bluesleep_remove(struct platform_device *pdev)
return 0;
}
-
static int bluesleep_resume(struct platform_device *pdev)
{
-
pr_debug("%s", __func__);
if (test_bit(BT_SUSPEND, &flags)) {
-
- if ((bsi->uport != NULL) && (bsi->has_ext_wake)) {
- tegra_uart_request_clock_on(bsi->uport);
- tegra_uart_set_mctrl(bsi->uport, TIOCM_RTS);
- }
+ free_irq(bsi->host_wake_irq, "tibluesleep");
clear_bit(BT_SUSPEND, &flags);
set_bit(BT_ACTIVE, &flags);
}
@@ -317,6 +213,7 @@ static struct platform_driver bluesleep_driver = {
.owner = THIS_MODULE,
},
};
+
/**
* Initializes the module.
* @return On success, 0. On error, -1, and <code>errno</code> is set
@@ -337,12 +234,6 @@ static int __init bluesleep_init(void)
flags = FLAG_RESET; /* clear all status bits */
- /* Initialize spinlock. */
- spin_lock_init(&rw_lock);
-
- /* initialize host wake tasklet */
- tasklet_init(&hostwake_task, bluesleep_hostwake_task, 0);
-
return 0;
fail:
return retval;
@@ -351,7 +242,6 @@ fail:
/**
* Cleans up the module.
*/
-
static void __exit bluesleep_exit(void)
{
if (bsi == NULL)
diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
index 6db161f64ae0..a9a113782821 100644
--- a/drivers/clk/clkdev.c
+++ b/drivers/clk/clkdev.c
@@ -89,6 +89,51 @@ void clk_put(struct clk *clk)
}
EXPORT_SYMBOL(clk_put);
+static void devm_clk_release(struct device *dev, void *res)
+{
+ clk_put(*(struct clk **)res);
+}
+
+struct clk *devm_clk_get(struct device *dev, const char *id)
+{
+ struct clk **ptr, *clk;
+
+ ptr = devres_alloc(devm_clk_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ clk = clk_get(dev, id);
+ if (!IS_ERR(clk)) {
+ *ptr = clk;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ }
+
+ return clk;
+}
+EXPORT_SYMBOL(devm_clk_get);
+
+static int devm_clk_match(struct device *dev, void *res, void *data)
+{
+ struct clk **c = res;
+ if (!c || !*c) {
+ WARN_ON(!c || !*c);
+ return 0;
+ }
+ return *c == data;
+}
+
+void devm_clk_put(struct device *dev, struct clk *clk)
+{
+ int ret;
+
+ ret = devres_destroy(dev, devm_clk_release, devm_clk_match, clk);
+
+ WARN_ON(ret);
+}
+EXPORT_SYMBOL(devm_clk_put);
+
void clkdev_add(struct clk_lookup *cl)
{
mutex_lock(&clocks_mutex);
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 3acc42805e21..02e8c9120d6b 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -1640,9 +1640,9 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
unsigned int pmax = policy->max;
qmin = min((unsigned int)pm_qos_request(PM_QOS_CPU_FREQ_MIN),
- data->max);
+ data->user_policy.max);
qmax = max((unsigned int)pm_qos_request(PM_QOS_CPU_FREQ_MAX),
- data->min);
+ data->user_policy.min);
pr_debug("setting new policy for CPU %u: %u - %u (%u - %u) kHz\n",
policy->cpu, pmin, pmax, qmin, qmax);
@@ -1654,7 +1654,8 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
memcpy(&policy->cpuinfo, &data->cpuinfo,
sizeof(struct cpufreq_cpuinfo));
- if (policy->min > data->max || policy->max < data->min) {
+ if (policy->min > data->user_policy.max ||
+ policy->max < data->user_policy.min) {
ret = -EINVAL;
goto error_out;
}
@@ -1785,6 +1786,70 @@ no_policy:
}
EXPORT_SYMBOL(cpufreq_update_policy);
+/*
+ * cpufreq_set_gov - set governor for a cpu
+ * @cpu: CPU whose governor needs to be changed
+ * @target_gov: new governor to be set
+ */
+int cpufreq_set_gov(char *target_gov, unsigned int cpu)
+{
+ int ret = 0;
+ struct cpufreq_policy new_policy;
+ struct cpufreq_policy *cur_policy;
+
+ if (target_gov == NULL)
+ return -EINVAL;
+
+ /* Get current governer */
+ cur_policy = cpufreq_cpu_get(cpu);
+ if (!cur_policy)
+ return -EINVAL;
+
+ if (lock_policy_rwsem_read(cur_policy->cpu) < 0) {
+ ret = -EINVAL;
+ goto err_out;
+ }
+
+ if (cur_policy->governor)
+ ret = strncmp(cur_policy->governor->name, target_gov,
+ strlen(target_gov));
+ else {
+ unlock_policy_rwsem_read(cur_policy->cpu);
+ ret = -EINVAL;
+ goto err_out;
+ }
+ unlock_policy_rwsem_read(cur_policy->cpu);
+
+ if (!ret) {
+ pr_debug(" Target governer & current governer is same\n");
+ ret = -EINVAL;
+ goto err_out;
+ } else {
+ new_policy = *cur_policy;
+ if (cpufreq_parse_governor(target_gov, &new_policy.policy,
+ &new_policy.governor)) {
+ ret = -EINVAL;
+ goto err_out;
+ }
+
+ if (lock_policy_rwsem_write(cur_policy->cpu) < 0) {
+ ret = -EINVAL;
+ goto err_out;
+ }
+
+ ret = __cpufreq_set_policy(cur_policy, &new_policy);
+
+ cur_policy->user_policy.policy = cur_policy->policy;
+ cur_policy->user_policy.governor = cur_policy->governor;
+
+ unlock_policy_rwsem_write(cur_policy->cpu);
+ }
+err_out:
+ cpufreq_cpu_put(cur_policy);
+ return ret;
+}
+EXPORT_SYMBOL(cpufreq_set_gov);
+
static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb,
unsigned long action, void *hcpu)
{
diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c
index 2012d5a51889..baf4326e84c4 100644
--- a/drivers/cpufreq/cpufreq_interactive.c
+++ b/drivers/cpufreq/cpufreq_interactive.c
@@ -2,6 +2,7 @@
* drivers/cpufreq/cpufreq_interactive.c
*
* Copyright (C) 2010 Google, Inc.
+ * Copyright (c) 2012, NVIDIA CORPORATION. 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
@@ -91,6 +92,13 @@ static unsigned long min_sample_time;
#define DEFAULT_TIMER_RATE 20000;
static unsigned long timer_rate;
+/* Defines to control mid-range frequencies */
+#define DEFAULT_MID_RANGE_GO_MAXSPEED_LOAD 95
+
+static unsigned long midrange_freq;
+static unsigned long midrange_go_maxspeed_load;
+static unsigned long midrange_max_boost;
+
static int cpufreq_governor_interactive(struct cpufreq_policy *policy,
unsigned int event);
@@ -108,6 +116,8 @@ static unsigned int cpufreq_interactive_get_target(
int cpu_load, int load_since_change, struct cpufreq_policy *policy)
{
unsigned int target_freq;
+ unsigned int maxspeed_load = go_maxspeed_load;
+ unsigned int mboost = max_boost;
/*
* Choose greater of short-term load (since last idle timer
@@ -117,14 +127,19 @@ static unsigned int cpufreq_interactive_get_target(
if (load_since_change > cpu_load)
cpu_load = load_since_change;
- if (cpu_load >= go_maxspeed_load) {
+ if (midrange_freq && policy->cur > midrange_freq) {
+ maxspeed_load = midrange_go_maxspeed_load;
+ mboost = midrange_max_boost;
+ }
+
+ if (cpu_load >= maxspeed_load) {
if (!boost_factor)
return policy->max;
target_freq = policy->cur * boost_factor;
- if (max_boost && target_freq > policy->cur + max_boost)
- target_freq = policy->cur + max_boost;
+ if (mboost && target_freq > policy->cur + mboost)
+ target_freq = policy->cur + mboost;
}
else {
if (!sustain_load)
@@ -527,6 +542,50 @@ static ssize_t store_go_maxspeed_load(struct kobject *kobj,
static struct global_attr go_maxspeed_load_attr = __ATTR(go_maxspeed_load, 0644,
show_go_maxspeed_load, store_go_maxspeed_load);
+static ssize_t show_midrange_freq(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ return sprintf(buf, "%lu\n", midrange_freq);
+}
+
+static ssize_t store_midrange_freq(struct kobject *kobj,
+ struct attribute *attr, const char *buf, size_t count)
+{
+ int ret;
+ unsigned long val;
+
+ ret = strict_strtoul(buf, 0, &val);
+ if (ret < 0)
+ return ret;
+ midrange_freq = val;
+ return count;
+}
+
+static struct global_attr midrange_freq_attr = __ATTR(midrange_freq, 0644,
+ show_midrange_freq, store_midrange_freq);
+
+static ssize_t show_midrange_go_maxspeed_load(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ return sprintf(buf, "%lu\n", midrange_go_maxspeed_load);
+}
+
+static ssize_t store_midrange_go_maxspeed_load(struct kobject *kobj,
+ struct attribute *attr, const char *buf, size_t count)
+{
+ int ret;
+ unsigned long val;
+
+ ret = strict_strtoul(buf, 0, &val);
+ if (ret < 0)
+ return ret;
+ midrange_go_maxspeed_load = val;
+ return count;
+}
+
+static struct global_attr midrange_go_maxspeed_load_attr = __ATTR(midrange_go_maxspeed_load, 0644,
+ show_midrange_go_maxspeed_load, store_midrange_go_maxspeed_load);
+
static ssize_t show_boost_factor(struct kobject *kobj,
struct attribute *attr, char *buf)
{
@@ -588,6 +647,27 @@ static ssize_t store_max_boost(struct kobject *kobj,
static struct global_attr max_boost_attr = __ATTR(max_boost, 0644,
show_max_boost, store_max_boost);
+static ssize_t show_midrange_max_boost(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ return sprintf(buf, "%lu\n", midrange_max_boost);
+}
+
+static ssize_t store_midrange_max_boost(struct kobject *kobj,
+ struct attribute *attr, const char *buf, size_t count)
+{
+ int ret;
+ unsigned long val;
+
+ ret = strict_strtoul(buf, 0, &val);
+ if (ret < 0)
+ return ret;
+ midrange_max_boost = val;
+ return count;
+}
+
+static struct global_attr midrange_max_boost_attr = __ATTR(midrange_max_boost, 0644,
+ show_midrange_max_boost, store_midrange_max_boost);
static ssize_t show_sustain_load(struct kobject *kobj,
struct attribute *attr, char *buf)
@@ -657,8 +737,11 @@ static struct global_attr timer_rate_attr = __ATTR(timer_rate, 0644,
static struct attribute *interactive_attributes[] = {
&go_maxspeed_load_attr.attr,
+ &midrange_freq_attr.attr,
+ &midrange_go_maxspeed_load_attr.attr,
&boost_factor_attr.attr,
&max_boost_attr.attr,
+ &midrange_max_boost_attr.attr,
&io_is_busy_attr.attr,
&sustain_load_attr.attr,
&min_sample_time_attr.attr,
@@ -787,6 +870,7 @@ static int __init cpufreq_interactive_init(void)
struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
go_maxspeed_load = DEFAULT_GO_MAXSPEED_LOAD;
+ midrange_go_maxspeed_load = DEFAULT_MID_RANGE_GO_MAXSPEED_LOAD;
min_sample_time = DEFAULT_MIN_SAMPLE_TIME;
timer_rate = DEFAULT_TIMER_RATE;
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index c136b787c5af..1957eee7549e 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -355,6 +355,7 @@ static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb,
cpufreq_update_policy(cpu);
break;
case CPU_DOWN_PREPARE:
+ case CPU_DOWN_PREPARE_FROZEN:
cpufreq_stats_free_sysfs(cpu);
break;
case CPU_DEAD:
diff --git a/drivers/cpuquiet/Kconfig b/drivers/cpuquiet/Kconfig
new file mode 100644
index 000000000000..844cd34a69b3
--- /dev/null
+++ b/drivers/cpuquiet/Kconfig
@@ -0,0 +1,11 @@
+menu "CPUQUIET Framework"
+
+config CPUQUIET_FRAMEWORK
+ bool "Cpuquiet framework"
+ default n
+ help
+ Cpuquiet implements pluggable policies for forcing cpu cores into a
+ quiescent state. Appropriate policies will save power without hurting
+ performance.
+
+endmenu
diff --git a/drivers/cpuquiet/Makefile b/drivers/cpuquiet/Makefile
new file mode 100644
index 000000000000..e438defaacdd
--- /dev/null
+++ b/drivers/cpuquiet/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_CPUQUIET_FRAMEWORK) += cpuquiet.o driver.o sysfs.o cpuquiet_attribute.o governor.o governors/
diff --git a/drivers/cpuquiet/cpuquiet.c b/drivers/cpuquiet/cpuquiet.c
new file mode 100644
index 000000000000..d902af26c8d7
--- /dev/null
+++ b/drivers/cpuquiet/cpuquiet.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2012 NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/cpu.h>
+#include <linux/slab.h>
+#include <linux/cpuquiet.h>
+#include "cpuquiet.h"
+
+DEFINE_MUTEX(cpuquiet_lock);
+
+static int __init cpuquiet_init(void)
+{
+ return cpuquiet_add_class_sysfs(&cpu_sysdev_class);
+}
+
+core_initcall(cpuquiet_init);
diff --git a/drivers/cpuquiet/cpuquiet.h b/drivers/cpuquiet/cpuquiet.h
new file mode 100644
index 000000000000..fa61946ff119
--- /dev/null
+++ b/drivers/cpuquiet/cpuquiet.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2012 NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __DRIVER_CPUQUIET_H
+#define __DRIVER_CPUQUIET_H
+
+#include <linux/sysdev.h>
+
+extern struct mutex cpuquiet_lock;
+extern struct cpuquiet_governor *cpuquiet_curr_governor;
+extern struct list_head cpuquiet_governors;
+int cpuquiet_add_class_sysfs(struct sysdev_class *cls);
+struct cpuquiet_governor *cpuquiet_find_governor(const char *str);
+int cpuquiet_switch_governor(struct cpuquiet_governor *gov);
+struct cpuquiet_governor *cpuquiet_get_first_governor(void);
+struct cpuquiet_driver *cpuquiet_get_driver(void);
+void cpuquiet_add_dev(struct sys_device *sys_dev, unsigned int cpu);
+void cpuquiet_remove_dev(unsigned int cpu);
+int cpuquiet_cpu_kobject_init(struct kobject *kobj, struct kobj_type *type,
+ char *name, int cpu);
+#endif
diff --git a/drivers/cpuquiet/cpuquiet_attribute.c b/drivers/cpuquiet/cpuquiet_attribute.c
new file mode 100644
index 000000000000..9f1aa430149d
--- /dev/null
+++ b/drivers/cpuquiet/cpuquiet_attribute.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2012 NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/cpuquiet.h>
+
+ssize_t show_int_attribute(struct cpuquiet_attribute *cattr, char *buf)
+{
+ return sprintf(buf, "%d\n", *((int *)cattr->param));
+}
+
+ssize_t store_int_attribute(struct cpuquiet_attribute *cattr,
+ const char *buf, size_t count)
+{
+ int err, val;
+
+ err = kstrtoint(buf, 0, &val);
+ if (err < 0)
+ return err;
+
+ *((int *)(cattr->param)) = val;
+
+ if (cattr->store_callback)
+ cattr->store_callback(cattr);
+
+ return count;
+}
+
+ssize_t show_bool_attribute(struct cpuquiet_attribute *cattr, char *buf)
+{
+ return sprintf(buf, "%d\n", *((bool *)cattr->param));
+}
+
+ssize_t store_bool_attribute(struct cpuquiet_attribute *cattr,
+ const char *buf, size_t count)
+{
+ int err, val;
+
+ err = kstrtoint(buf, 0, &val);
+ if (err < 0)
+ return err;
+
+ if (val < 0 || val > 1)
+ return -EINVAL;
+
+ *((bool *)(cattr->param)) = val;
+
+ if (cattr->store_callback)
+ cattr->store_callback(cattr);
+
+ return count;
+}
+
+ssize_t show_uint_attribute(struct cpuquiet_attribute *cattr, char *buf)
+{
+ return sprintf(buf, "%u\n", *((unsigned int *)cattr->param));
+}
+
+ssize_t store_uint_attribute(struct cpuquiet_attribute *cattr,
+ const char *buf, size_t count)
+{
+ int err;
+ unsigned int val;
+
+ err = kstrtouint(buf, 0, &val);
+ if (err < 0)
+ return err;
+
+ *((unsigned int *)(cattr->param)) = val;
+
+ if (cattr->store_callback)
+ cattr->store_callback(cattr);
+
+ return count;
+}
+
+ssize_t store_ulong_attribute(struct cpuquiet_attribute *cattr,
+ const char *buf, size_t count)
+{
+ int err;
+ unsigned long val;
+
+ err = kstrtoul(buf, 0, &val);
+ if (err < 0)
+ return err;
+
+ *((unsigned long *)(cattr->param)) = val;
+
+ if (cattr->store_callback)
+ cattr->store_callback(cattr);
+
+ return count;
+}
+
+ssize_t show_ulong_attribute(struct cpuquiet_attribute *cattr,
+ char *buf)
+{
+ return sprintf(buf, "%lu\n", *((unsigned long *)cattr->param));
+}
+
+ssize_t cpuquiet_auto_sysfs_store(struct kobject *kobj,
+ struct attribute *attr, const char *buf, size_t count)
+{
+ struct cpuquiet_attribute *cattr =
+ container_of(attr, struct cpuquiet_attribute, attr);
+
+ if (cattr->store)
+ return cattr->store(cattr, buf, count);
+
+ return -EINVAL;
+}
+
+ssize_t cpuquiet_auto_sysfs_show(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ struct cpuquiet_attribute *cattr =
+ container_of(attr, struct cpuquiet_attribute, attr);
+
+ return cattr->show(cattr, buf);
+}
diff --git a/drivers/cpuquiet/driver.c b/drivers/cpuquiet/driver.c
new file mode 100644
index 000000000000..d9dbea76994a
--- /dev/null
+++ b/drivers/cpuquiet/driver.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2012 NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/cpuquiet.h>
+#include <linux/cpu.h>
+#include <linux/jiffies.h>
+#include <linux/slab.h>
+#include <asm/cputime.h>
+
+#include "cpuquiet.h"
+
+struct cpuquiet_cpu_stat {
+ cputime64_t time_up_total;
+ u64 last_update;
+ unsigned int up_down_count;
+ struct kobject cpu_kobject;
+};
+
+struct cpu_attribute {
+ struct attribute attr;
+ enum { up_down_count, time_up_total } type;
+};
+
+static struct cpuquiet_driver *cpuquiet_curr_driver;
+struct cpuquiet_cpu_stat *stats;
+
+#define CPU_ATTRIBUTE(_name) \
+ static struct cpu_attribute _name ## _attr = { \
+ .attr = {.name = __stringify(_name), .mode = 0444 }, \
+ .type = _name, \
+}
+
+CPU_ATTRIBUTE(up_down_count);
+CPU_ATTRIBUTE(time_up_total);
+
+static struct attribute *cpu_attributes[] = {
+ &up_down_count_attr.attr,
+ &time_up_total_attr.attr,
+ NULL,
+};
+
+static void stats_update(struct cpuquiet_cpu_stat *stat, bool up)
+{
+ u64 cur_jiffies = get_jiffies_64();
+ bool was_up = stat->up_down_count & 0x1;
+
+ if (was_up)
+ stat->time_up_total = cputime64_add(stat->time_up_total,
+ cputime64_sub(cur_jiffies, stat->last_update));
+
+ if (was_up != up)
+ stat->up_down_count++;
+
+ stat->last_update = cur_jiffies;
+}
+
+int cpuquiet_quiesence_cpu(unsigned int cpunumber)
+{
+ int err = -EPERM;
+
+ if (cpuquiet_curr_driver && cpuquiet_curr_driver->quiesence_cpu)
+ err = cpuquiet_curr_driver->quiesence_cpu(cpunumber);
+
+ if (!err)
+ stats_update(stats + cpunumber, 0);
+
+ return err;
+}
+EXPORT_SYMBOL(cpuquiet_quiesence_cpu);
+
+int cpuquiet_wake_cpu(unsigned int cpunumber)
+{
+ int err = -EPERM;
+
+ if (cpuquiet_curr_driver && cpuquiet_curr_driver->wake_cpu)
+ err = cpuquiet_curr_driver->wake_cpu(cpunumber);
+
+ if (!err)
+ stats_update(stats + cpunumber, 1);
+
+ return err;
+}
+EXPORT_SYMBOL(cpuquiet_wake_cpu);
+
+static ssize_t stats_sysfs_show(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ struct cpu_attribute *cattr =
+ container_of(attr, struct cpu_attribute, attr);
+ struct cpuquiet_cpu_stat *stat =
+ container_of(kobj, struct cpuquiet_cpu_stat, cpu_kobject);
+ ssize_t len = 0;
+ bool was_up = stat->up_down_count & 0x1;
+
+ stats_update(stat, was_up);
+
+ switch (cattr->type) {
+ case up_down_count:
+ len = sprintf(buf, "%u\n", stat->up_down_count);
+ break;
+ case time_up_total:
+ len = sprintf(buf, "%llu\n", stat->time_up_total);
+ break;
+ }
+
+ return len;
+}
+
+static const struct sysfs_ops stats_sysfs_ops = {
+ .show = stats_sysfs_show,
+};
+
+static struct kobj_type ktype_cpu_stats = {
+ .sysfs_ops = &stats_sysfs_ops,
+ .default_attrs = cpu_attributes,
+};
+
+int cpuquiet_register_driver(struct cpuquiet_driver *drv)
+{
+ int err = -EBUSY;
+ unsigned int cpu;
+ struct sys_device *sys_dev;
+ u64 cur_jiffies;
+
+ if (!drv)
+ return -EINVAL;
+
+ stats = kzalloc(nr_cpu_ids * sizeof(*stats), GFP_KERNEL);
+ if (!stats)
+ return -ENOMEM;
+
+ for_each_possible_cpu(cpu) {
+ cur_jiffies = get_jiffies_64();
+ stats[cpu].last_update = cur_jiffies;
+ if (cpu_online(cpu))
+ stats[cpu].up_down_count = 1;
+ sys_dev = get_cpu_sysdev(cpu);
+ if (sys_dev) {
+ cpuquiet_add_dev(sys_dev, cpu);
+ cpuquiet_cpu_kobject_init(&stats[cpu].cpu_kobject,
+ &ktype_cpu_stats, "stats", cpu);
+ }
+ }
+
+ mutex_lock(&cpuquiet_lock);
+ if (!cpuquiet_curr_driver) {
+ err = 0;
+ cpuquiet_curr_driver = drv;
+ cpuquiet_switch_governor(cpuquiet_get_first_governor());
+ }
+ mutex_unlock(&cpuquiet_lock);
+
+ return err;
+}
+EXPORT_SYMBOL(cpuquiet_register_driver);
+
+struct cpuquiet_driver *cpuquiet_get_driver(void)
+{
+ return cpuquiet_curr_driver;
+}
+
+void cpuquiet_unregister_driver(struct cpuquiet_driver *drv)
+{
+ unsigned int cpu;
+
+ if (drv != cpuquiet_curr_driver) {
+ WARN(1, "invalid cpuquiet_unregister_driver(%s)\n",
+ drv->name);
+ return;
+ }
+
+ /* stop current governor first */
+ cpuquiet_switch_governor(NULL);
+
+ mutex_lock(&cpuquiet_lock);
+ cpuquiet_curr_driver = NULL;
+
+ for_each_possible_cpu(cpu) {
+ kobject_put(&stats[cpu].cpu_kobject);
+ cpuquiet_remove_dev(cpu);
+ }
+
+ mutex_unlock(&cpuquiet_lock);
+}
+EXPORT_SYMBOL(cpuquiet_unregister_driver);
diff --git a/drivers/cpuquiet/governor.c b/drivers/cpuquiet/governor.c
new file mode 100644
index 000000000000..7895fccc7f42
--- /dev/null
+++ b/drivers/cpuquiet/governor.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2012 NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/cpuquiet.h>
+
+#include "cpuquiet.h"
+
+LIST_HEAD(cpuquiet_governors);
+struct cpuquiet_governor *cpuquiet_curr_governor;
+
+struct cpuquiet_governor *cpuquiet_get_first_governor(void)
+{
+ if (!list_empty(&cpuquiet_governors))
+ return list_entry(cpuquiet_governors.next,
+ struct cpuquiet_governor,
+ governor_list);
+ else
+ return NULL;
+}
+
+struct cpuquiet_governor *cpuquiet_find_governor(const char *str)
+{
+ struct cpuquiet_governor *gov;
+
+ list_for_each_entry(gov, &cpuquiet_governors, governor_list)
+ if (!strnicmp(str, gov->name, CPUQUIET_NAME_LEN))
+ return gov;
+
+ return NULL;
+}
+
+int cpuquiet_switch_governor(struct cpuquiet_governor *gov)
+{
+ int err = 0;
+
+ if (cpuquiet_curr_governor) {
+ if (cpuquiet_curr_governor->stop)
+ cpuquiet_curr_governor->stop();
+ module_put(cpuquiet_curr_governor->owner);
+ }
+
+ cpuquiet_curr_governor = gov;
+
+ if (gov) {
+ if (!try_module_get(cpuquiet_curr_governor->owner))
+ return -EINVAL;
+ if (gov->start)
+ err = gov->start();
+ if (!err)
+ cpuquiet_curr_governor = gov;
+ }
+
+ return err;
+}
+
+int cpuquiet_register_governor(struct cpuquiet_governor *gov)
+{
+ int ret = -EEXIST;
+
+ if (!gov)
+ return -EINVAL;
+
+ mutex_lock(&cpuquiet_lock);
+ if (cpuquiet_find_governor(gov->name) == NULL) {
+ ret = 0;
+ list_add_tail(&gov->governor_list, &cpuquiet_governors);
+ if (!cpuquiet_curr_governor && cpuquiet_get_driver())
+ cpuquiet_switch_governor(gov);
+ }
+ mutex_unlock(&cpuquiet_lock);
+
+ return ret;
+}
+
+void cpuquiet_unregister_governor(struct cpuquiet_governor *gov)
+{
+ if (!gov)
+ return;
+
+ mutex_lock(&cpuquiet_lock);
+ if (cpuquiet_curr_governor == gov)
+ cpuquiet_switch_governor(NULL);
+ list_del(&gov->governor_list);
+ mutex_unlock(&cpuquiet_lock);
+}
diff --git a/drivers/cpuquiet/governors/Makefile b/drivers/cpuquiet/governors/Makefile
new file mode 100644
index 000000000000..c70803127082
--- /dev/null
+++ b/drivers/cpuquiet/governors/Makefile
@@ -0,0 +1 @@
+obj-y += userspace.o balanced.o
diff --git a/drivers/cpuquiet/governors/balanced.c b/drivers/cpuquiet/governors/balanced.c
new file mode 100644
index 000000000000..f0d2e03ae22b
--- /dev/null
+++ b/drivers/cpuquiet/governors/balanced.c
@@ -0,0 +1,461 @@
+/*
+ * Copyright (c) 2012 NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/cpuquiet.h>
+#include <linux/cpumask.h>
+#include <linux/module.h>
+#include <linux/cpufreq.h>
+#include <linux/pm_qos_params.h>
+#include <linux/jiffies.h>
+#include <linux/slab.h>
+#include <linux/cpu.h>
+#include <linux/sched.h>
+#include <linux/tick.h>
+#include <asm/cputime.h>
+
+#define CPUNAMELEN 8
+
+typedef enum {
+ CPU_SPEED_BALANCED,
+ CPU_SPEED_BIASED,
+ CPU_SPEED_SKEWED,
+} CPU_SPEED_BALANCE;
+
+typedef enum {
+ IDLE,
+ DOWN,
+ UP,
+} BALANCED_STATE;
+
+struct idle_info {
+ u64 idle_last;
+ u64 last_timestamp;
+ u64 idle_current;
+ u64 timestamp;
+};
+
+static DEFINE_PER_CPU(struct idle_info, idleinfo);
+static DEFINE_PER_CPU(unsigned int, cpu_load);
+
+static struct timer_list load_timer;
+static bool load_timer_active;
+
+/* configurable parameters */
+static unsigned int balance_level = 60;
+static unsigned int idle_bottom_freq;
+static unsigned int idle_top_freq;
+static unsigned long up_delay;
+static unsigned long down_delay;
+static unsigned long last_change_time;
+static unsigned int load_sample_rate = 20; /* msec */
+static struct workqueue_struct *balanced_wq;
+static struct delayed_work balanced_work;
+static BALANCED_STATE balanced_state;
+static struct kobject *balanced_kobject;
+
+static void calculate_load_timer(unsigned long data)
+{
+ int i;
+ u64 idle_time, elapsed_time;
+
+ if (!load_timer_active)
+ return;
+
+ for_each_online_cpu(i) {
+ struct idle_info *iinfo = &per_cpu(idleinfo, i);
+ unsigned int *load = &per_cpu(cpu_load, i);
+
+ iinfo->idle_last = iinfo->idle_current;
+ iinfo->last_timestamp = iinfo->timestamp;
+ iinfo->idle_current =
+ get_cpu_idle_time_us(i, &iinfo->timestamp);
+ elapsed_time = iinfo->timestamp - iinfo->last_timestamp;
+
+ idle_time = iinfo->idle_current - iinfo->idle_last;
+ idle_time *= 100;
+ do_div(idle_time, elapsed_time);
+ *load = 100 - idle_time;
+ }
+ mod_timer(&load_timer, jiffies + msecs_to_jiffies(load_sample_rate));
+}
+
+static void start_load_timer(void)
+{
+ int i;
+
+ if (load_timer_active)
+ return;
+
+ load_timer_active = true;
+
+ for_each_online_cpu(i) {
+ struct idle_info *iinfo = &per_cpu(idleinfo, i);
+
+ iinfo->idle_current =
+ get_cpu_idle_time_us(i, &iinfo->timestamp);
+ }
+ mod_timer(&load_timer, jiffies + msecs_to_jiffies(100));
+}
+
+static void stop_load_timer(void)
+{
+ if (!load_timer_active)
+ return;
+
+ load_timer_active = false;
+ del_timer(&load_timer);
+}
+
+static unsigned int get_slowest_cpu_n(void)
+{
+ unsigned int cpu = nr_cpu_ids;
+ unsigned long minload = ULONG_MAX;
+ int i;
+
+ for_each_online_cpu(i) {
+ unsigned int *load = &per_cpu(cpu_load, i);
+
+ if ((i > 0) && (minload > *load)) {
+ cpu = i;
+ minload = *load;
+ }
+ }
+
+ return cpu;
+}
+
+static unsigned int cpu_highest_speed(void)
+{
+ unsigned int maxload = 0;
+ int i;
+
+ for_each_online_cpu(i) {
+ unsigned int *load = &per_cpu(cpu_load, i);
+
+ maxload = max(maxload, *load);
+ }
+
+ return maxload;
+}
+
+static unsigned int count_slow_cpus(unsigned int limit)
+{
+ unsigned int cnt = 0;
+ int i;
+
+ for_each_online_cpu(i) {
+ unsigned int *load = &per_cpu(cpu_load, i);
+
+ if (*load <= limit)
+ cnt++;
+ }
+
+ return cnt;
+}
+
+#define NR_FSHIFT 2
+static unsigned int nr_run_thresholds[] = {
+/* 1, 2, 3, 4 - on-line cpus target */
+ 5, 9, 10, UINT_MAX /* avg run threads * 4 (e.g., 9 = 2.25 threads) */
+};
+static unsigned int nr_run_hysteresis = 2; /* 0.5 thread */
+static unsigned int nr_run_last;
+
+static CPU_SPEED_BALANCE balanced_speed_balance(void)
+{
+ unsigned long highest_speed = cpu_highest_speed();
+ unsigned long balanced_speed = highest_speed * balance_level / 100;
+ unsigned long skewed_speed = balanced_speed / 2;
+ unsigned int nr_cpus = num_online_cpus();
+ unsigned int max_cpus = pm_qos_request(PM_QOS_MAX_ONLINE_CPUS) ? : 4;
+ unsigned int avg_nr_run = avg_nr_running();
+ unsigned int nr_run;
+
+ /* balanced: freq targets for all CPUs are above 50% of highest speed
+ biased: freq target for at least one CPU is below 50% threshold
+ skewed: freq targets for at least 2 CPUs are below 25% threshold */
+ for (nr_run = 1; nr_run < ARRAY_SIZE(nr_run_thresholds); nr_run++) {
+ unsigned int nr_threshold = nr_run_thresholds[nr_run - 1];
+ if (nr_run_last <= nr_run)
+ nr_threshold += nr_run_hysteresis;
+ if (avg_nr_run <= (nr_threshold << (FSHIFT - NR_FSHIFT)))
+ break;
+ }
+ nr_run_last = nr_run;
+
+ if (count_slow_cpus(skewed_speed) >= 2 || nr_cpus > max_cpus ||
+ nr_run < nr_cpus)
+ return CPU_SPEED_SKEWED;
+
+ if (count_slow_cpus(balanced_speed) >= 1 || nr_cpus == max_cpus ||
+ nr_run <= nr_cpus)
+ return CPU_SPEED_BIASED;
+
+ return CPU_SPEED_BALANCED;
+}
+
+static void balanced_work_func(struct work_struct *work)
+{
+ bool up = false;
+ unsigned int cpu = nr_cpu_ids;
+ unsigned long now = jiffies;
+
+ CPU_SPEED_BALANCE balance;
+
+ switch (balanced_state) {
+ case IDLE:
+ break;
+ case DOWN:
+ cpu = get_slowest_cpu_n();
+ if (cpu < nr_cpu_ids) {
+ up = false;
+ queue_delayed_work(balanced_wq,
+ &balanced_work, up_delay);
+ } else
+ stop_load_timer();
+ break;
+ case UP:
+ balance = balanced_speed_balance();
+ switch (balance) {
+
+ /* cpu speed is up and balanced - one more on-line */
+ case CPU_SPEED_BALANCED:
+ cpu = cpumask_next_zero(0, cpu_online_mask);
+ if (cpu < nr_cpu_ids)
+ up = true;
+ break;
+ /* cpu speed is up, but skewed - remove one core */
+ case CPU_SPEED_SKEWED:
+ cpu = get_slowest_cpu_n();
+ if (cpu < nr_cpu_ids)
+ up = false;
+ break;
+ /* cpu speed is up, but under-utilized - do nothing */
+ case CPU_SPEED_BIASED:
+ default:
+ break;
+ }
+ queue_delayed_work(
+ balanced_wq, &balanced_work, up_delay);
+ break;
+ default:
+ pr_err("%s: invalid cpuquiet balanced governor state %d\n",
+ __func__, balanced_state);
+ }
+
+ if (!up && ((now - last_change_time) < down_delay))
+ cpu = nr_cpu_ids;
+
+ if (cpu < nr_cpu_ids) {
+ last_change_time = now;
+ if (up)
+ cpuquiet_wake_cpu(cpu);
+ else
+ cpuquiet_quiesence_cpu(cpu);
+ }
+}
+
+static int balanced_cpufreq_transition(struct notifier_block *nb,
+ unsigned long state, void *data)
+{
+ struct cpufreq_freqs *freqs = data;
+ unsigned long cpu_freq;
+
+ if (state == CPUFREQ_POSTCHANGE || state == CPUFREQ_RESUMECHANGE) {
+ cpu_freq = freqs->new;
+
+ switch (balanced_state) {
+ case IDLE:
+ if (cpu_freq >= idle_top_freq) {
+ balanced_state = UP;
+ queue_delayed_work(
+ balanced_wq, &balanced_work, up_delay);
+ start_load_timer();
+ } else if (cpu_freq <= idle_bottom_freq) {
+ balanced_state = DOWN;
+ queue_delayed_work(
+ balanced_wq, &balanced_work,
+ down_delay);
+ start_load_timer();
+ }
+ break;
+ case DOWN:
+ if (cpu_freq >= idle_top_freq) {
+ balanced_state = UP;
+ queue_delayed_work(
+ balanced_wq, &balanced_work, up_delay);
+ start_load_timer();
+ }
+ break;
+ case UP:
+ if (cpu_freq <= idle_bottom_freq) {
+ balanced_state = DOWN;
+ queue_delayed_work(balanced_wq,
+ &balanced_work, up_delay);
+ start_load_timer();
+ }
+ break;
+ default:
+ pr_err("%s: invalid cpuquiet balanced governor "
+ "state %d\n", __func__, balanced_state);
+ }
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block balanced_cpufreq_nb = {
+ .notifier_call = balanced_cpufreq_transition,
+};
+
+static void delay_callback(struct cpuquiet_attribute *attr)
+{
+ unsigned long val;
+
+ if (attr) {
+ val = (*((unsigned long *)(attr->param)));
+ (*((unsigned long *)(attr->param))) = msecs_to_jiffies(val);
+ }
+}
+
+CPQ_BASIC_ATTRIBUTE(balance_level, 0644, uint);
+CPQ_BASIC_ATTRIBUTE(idle_bottom_freq, 0644, uint);
+CPQ_BASIC_ATTRIBUTE(idle_top_freq, 0644, uint);
+CPQ_BASIC_ATTRIBUTE(load_sample_rate, 0644, uint);
+CPQ_ATTRIBUTE(up_delay, 0644, ulong, delay_callback);
+CPQ_ATTRIBUTE(down_delay, 0644, ulong, delay_callback);
+
+static struct attribute *balanced_attributes[] = {
+ &balance_level_attr.attr,
+ &idle_bottom_freq_attr.attr,
+ &idle_top_freq_attr.attr,
+ &up_delay_attr.attr,
+ &down_delay_attr.attr,
+ &load_sample_rate_attr.attr,
+ NULL,
+};
+
+static const struct sysfs_ops balanced_sysfs_ops = {
+ .show = cpuquiet_auto_sysfs_show,
+ .store = cpuquiet_auto_sysfs_store,
+};
+
+static struct kobj_type ktype_balanced = {
+ .sysfs_ops = &balanced_sysfs_ops,
+ .default_attrs = balanced_attributes,
+};
+
+static int balanced_sysfs(void)
+{
+ int err;
+
+ balanced_kobject = kzalloc(sizeof(*balanced_kobject),
+ GFP_KERNEL);
+
+ if (!balanced_kobject)
+ return -ENOMEM;
+
+ err = cpuquiet_kobject_init(balanced_kobject, &ktype_balanced,
+ "balanced");
+
+ if (err)
+ kfree(balanced_kobject);
+
+ return err;
+}
+
+static void balanced_stop(void)
+{
+ /*
+ first unregister the notifiers. This ensures the governor state
+ can't be modified by a cpufreq transition
+ */
+ cpufreq_unregister_notifier(&balanced_cpufreq_nb,
+ CPUFREQ_TRANSITION_NOTIFIER);
+
+ /* now we can force the governor to be idle */
+ balanced_state = IDLE;
+ cancel_delayed_work_sync(&balanced_work);
+ destroy_workqueue(balanced_wq);
+ del_timer(&load_timer);
+
+ kobject_put(balanced_kobject);
+}
+
+static int balanced_start(void)
+{
+ int err, count;
+ struct cpufreq_frequency_table *table;
+ struct cpufreq_freqs initial_freq;
+
+ err = balanced_sysfs();
+ if (err)
+ return err;
+
+ balanced_wq = alloc_workqueue("cpuquiet-balanced",
+ WQ_UNBOUND | WQ_RESCUER | WQ_FREEZABLE, 1);
+ if (!balanced_wq)
+ return -ENOMEM;
+
+ INIT_DELAYED_WORK(&balanced_work, balanced_work_func);
+
+ up_delay = msecs_to_jiffies(100);
+ down_delay = msecs_to_jiffies(500);
+
+ table = cpufreq_frequency_get_table(0);
+ for (count = 0; table[count].frequency != CPUFREQ_TABLE_END; count++);
+
+ idle_top_freq = table[(count / 2) - 1].frequency;
+ idle_bottom_freq = table[(count / 2) - 2].frequency;
+
+ cpufreq_register_notifier(&balanced_cpufreq_nb,
+ CPUFREQ_TRANSITION_NOTIFIER);
+
+ init_timer(&load_timer);
+ load_timer.function = calculate_load_timer;
+
+ /*FIXME: Kick start the state machine by faking a freq notification*/
+ initial_freq.new = cpufreq_get(0);
+ if (initial_freq.new != 0)
+ balanced_cpufreq_transition(NULL, CPUFREQ_RESUMECHANGE,
+ &initial_freq);
+ return 0;
+}
+
+struct cpuquiet_governor balanced_governor = {
+ .name = "balanced",
+ .start = balanced_start,
+ .stop = balanced_stop,
+ .owner = THIS_MODULE,
+};
+
+static int __init init_balanced(void)
+{
+ return cpuquiet_register_governor(&balanced_governor);
+}
+
+static void __exit exit_balanced(void)
+{
+ cpuquiet_unregister_governor(&balanced_governor);
+}
+
+MODULE_LICENSE("GPL");
+module_init(init_balanced);
+module_exit(exit_balanced);
+
diff --git a/drivers/cpuquiet/governors/userspace.c b/drivers/cpuquiet/governors/userspace.c
new file mode 100644
index 000000000000..470056c5e32a
--- /dev/null
+++ b/drivers/cpuquiet/governors/userspace.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2012 NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/cpuquiet.h>
+#include <linux/sysfs.h>
+
+static DEFINE_MUTEX(userspace_mutex);
+
+static int governor_set(unsigned int cpu, bool active)
+{
+ mutex_lock(&userspace_mutex);
+ if (active)
+ cpuquiet_wake_cpu(cpu);
+ else
+ cpuquiet_quiesence_cpu(cpu);
+ mutex_unlock(&userspace_mutex);
+
+ return 0;
+}
+
+struct cpuquiet_governor userspace_governor = {
+ .name = "userspace",
+ .store_active = governor_set,
+ .owner = THIS_MODULE,
+};
+
+static int __init init_usermode(void)
+{
+ return cpuquiet_register_governor(&userspace_governor);
+}
+
+static void __exit exit_usermode(void)
+{
+ cpuquiet_unregister_governor(&userspace_governor);
+}
+
+MODULE_LICENSE("GPL");
+module_init(init_usermode);
+module_exit(exit_usermode);
diff --git a/drivers/cpuquiet/sysfs.c b/drivers/cpuquiet/sysfs.c
new file mode 100644
index 000000000000..0d63eee37dce
--- /dev/null
+++ b/drivers/cpuquiet/sysfs.c
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 2012 NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/sysfs.h>
+#include <linux/slab.h>
+#include <linux/cpuquiet.h>
+
+#include "cpuquiet.h"
+
+struct cpuquiet_dev {
+ unsigned int cpu;
+ struct kobject kobj;
+};
+
+struct cpuquiet_sysfs_attr {
+ struct attribute attr;
+ ssize_t (*show)(char *);
+ ssize_t (*store)(const char *, size_t count);
+};
+
+static struct kobject *cpuquiet_global_kobject;
+struct cpuquiet_dev *cpuquiet_cpu_devices[CONFIG_NR_CPUS];
+
+static ssize_t show_current_governor(char *buf)
+{
+ ssize_t ret;
+
+ mutex_lock(&cpuquiet_lock);
+
+ if (cpuquiet_curr_governor)
+ ret = sprintf(buf, "%s\n", cpuquiet_curr_governor->name);
+ else
+ ret = sprintf(buf, "none\n");
+
+ mutex_unlock(&cpuquiet_lock);
+
+ return ret;
+
+}
+
+static ssize_t store_current_governor(const char *buf, size_t count)
+{
+ char name[CPUQUIET_NAME_LEN];
+ struct cpuquiet_governor *gov;
+ int len = count, ret = -EINVAL;
+
+ if (!len || len >= sizeof(name))
+ return -EINVAL;
+
+ memcpy(name, buf, count);
+ name[len] = '\0';
+ if (name[len - 1] == '\n')
+ name[--len] = '\0';
+
+ mutex_lock(&cpuquiet_lock);
+ gov = cpuquiet_find_governor(name);
+ mutex_unlock(&cpuquiet_lock);
+
+ if (gov)
+ ret = cpuquiet_switch_governor(gov);
+
+ if (ret)
+ return ret;
+ else
+ return count;
+}
+
+static ssize_t available_governors_show(char *buf)
+{
+ ssize_t ret = 0, len;
+ struct cpuquiet_governor *gov;
+
+ mutex_lock(&cpuquiet_lock);
+ if (!list_empty(&cpuquiet_governors)) {
+ list_for_each_entry(gov, &cpuquiet_governors, governor_list) {
+ len = sprintf(buf, "%s ", gov->name);
+ buf += len;
+ ret += len;
+ }
+ buf--;
+ *buf = '\n';
+ } else
+ ret = sprintf(buf, "none\n");
+
+ mutex_unlock(&cpuquiet_lock);
+
+ return ret;
+}
+
+struct cpuquiet_sysfs_attr attr_current_governor = __ATTR(current_governor,
+ 0644, show_current_governor, store_current_governor);
+struct cpuquiet_sysfs_attr attr_governors = __ATTR_RO(available_governors);
+
+
+static struct attribute *cpuquiet_default_attrs[] = {
+ &attr_current_governor.attr,
+ &attr_governors.attr,
+ NULL
+};
+
+static ssize_t cpuquiet_sysfs_show(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ struct cpuquiet_sysfs_attr *cattr =
+ container_of(attr, struct cpuquiet_sysfs_attr, attr);
+
+ return cattr->show(buf);
+}
+
+static ssize_t cpuquiet_sysfs_store(struct kobject *kobj,
+ struct attribute *attr, const char *buf, size_t count)
+{
+ struct cpuquiet_sysfs_attr *cattr =
+ container_of(attr, struct cpuquiet_sysfs_attr, attr);
+
+ if (cattr->store)
+ return cattr->store(buf, count);
+
+ return -EINVAL;
+}
+
+static const struct sysfs_ops cpuquiet_sysfs_ops = {
+ .show = cpuquiet_sysfs_show,
+ .store = cpuquiet_sysfs_store,
+};
+
+static struct kobj_type ktype_cpuquiet_sysfs = {
+ .sysfs_ops = &cpuquiet_sysfs_ops,
+ .default_attrs = cpuquiet_default_attrs,
+};
+
+int cpuquiet_add_group(struct attribute_group *attrs)
+{
+ return sysfs_create_group(cpuquiet_global_kobject, attrs);
+}
+
+void cpuquiet_remove_group(struct attribute_group *attrs)
+{
+ sysfs_remove_group(cpuquiet_global_kobject, attrs);
+}
+
+int cpuquiet_kobject_init(struct kobject *kobj, struct kobj_type *type,
+ char *name)
+{
+ int err;
+
+ err = kobject_init_and_add(kobj, type, cpuquiet_global_kobject, name);
+ if (!err)
+ kobject_uevent(kobj, KOBJ_ADD);
+
+ return err;
+}
+
+int cpuquiet_cpu_kobject_init(struct kobject *kobj, struct kobj_type *type,
+ char *name, int cpu)
+{
+ int err;
+
+ err = kobject_init_and_add(kobj, type, &cpuquiet_cpu_devices[cpu]->kobj,
+ name);
+ if (!err)
+ kobject_uevent(kobj, KOBJ_ADD);
+
+ return err;
+}
+
+int cpuquiet_add_class_sysfs(struct sysdev_class *cls)
+{
+ int err;
+
+ cpuquiet_global_kobject = kzalloc(sizeof(*cpuquiet_global_kobject),
+ GFP_KERNEL);
+ if (!cpuquiet_global_kobject)
+ return -ENOMEM;
+
+ err = kobject_init_and_add(cpuquiet_global_kobject,
+ &ktype_cpuquiet_sysfs, &cls->kset.kobj, "cpuquiet");
+ if (!err)
+ kobject_uevent(cpuquiet_global_kobject, KOBJ_ADD);
+
+ return err;
+}
+
+
+struct cpuquiet_attr {
+ struct attribute attr;
+ ssize_t (*show)(unsigned int, char *);
+ ssize_t (*store)(unsigned int, const char *, size_t count);
+};
+
+
+static ssize_t cpuquiet_state_show(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ struct cpuquiet_attr *cattr = container_of(attr,
+ struct cpuquiet_attr, attr);
+ struct cpuquiet_dev *dev = container_of(kobj,
+ struct cpuquiet_dev, kobj);
+
+ return cattr->show(dev->cpu, buf);
+}
+
+static ssize_t cpuquiet_state_store(struct kobject *kobj,
+ struct attribute *attr, const char *buf, size_t count)
+{
+ struct cpuquiet_attr *cattr = container_of(attr,
+ struct cpuquiet_attr, attr);
+ struct cpuquiet_dev *dev = container_of(kobj,
+ struct cpuquiet_dev, kobj);
+
+ if (cattr->store)
+ return cattr->store(dev->cpu, buf, count);
+
+ return -EINVAL;
+}
+
+static ssize_t show_active(unsigned int cpu, char *buf)
+{
+ return sprintf(buf, "%u\n", cpu_online(cpu));
+}
+
+static ssize_t store_active(unsigned int cpu, const char *value, size_t count)
+{
+ unsigned int active;
+ int ret;
+
+ if (!cpuquiet_curr_governor->store_active)
+ return -EINVAL;
+
+ ret = sscanf(value, "%u", &active);
+ if (ret != 1)
+ return -EINVAL;
+
+ cpuquiet_curr_governor->store_active(cpu, active);
+
+ return count;
+}
+
+struct cpuquiet_attr attr_active = __ATTR(active, 0644, show_active,
+ store_active);
+
+static struct attribute *cpuquiet_default_cpu_attrs[] = {
+ &attr_active.attr,
+ NULL
+};
+
+static const struct sysfs_ops cpuquiet_cpu_sysfs_ops = {
+ .show = cpuquiet_state_show,
+ .store = cpuquiet_state_store,
+};
+
+static struct kobj_type ktype_cpuquiet = {
+ .sysfs_ops = &cpuquiet_cpu_sysfs_ops,
+ .default_attrs = cpuquiet_default_cpu_attrs,
+};
+
+void cpuquiet_add_dev(struct sys_device *sys_dev, unsigned int cpu)
+{
+ struct cpuquiet_dev *dev;
+ int err;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ dev->cpu = cpu;
+ cpuquiet_cpu_devices[cpu] = dev;
+ err = kobject_init_and_add(&dev->kobj, &ktype_cpuquiet,
+ &sys_dev->kobj, "cpuquiet");
+ if (!err)
+ kobject_uevent(&dev->kobj, KOBJ_ADD);
+}
+
+void cpuquiet_remove_dev(unsigned int cpu)
+{
+ if (cpu < CONFIG_NR_CPUS && cpuquiet_cpu_devices[cpu])
+ kobject_put(&cpuquiet_cpu_devices[cpu]->kobj);
+}
diff --git a/drivers/crypto/tegra-aes.c b/drivers/crypto/tegra-aes.c
index 291cb4be5c39..85c1df63bebc 100644
--- a/drivers/crypto/tegra-aes.c
+++ b/drivers/crypto/tegra-aes.c
@@ -499,6 +499,10 @@ static int aes_set_key(struct tegra_aes_engine *eng, int slot_num)
memset(dd->bsev.ivkey_base, 0, AES_HW_KEY_TABLE_LENGTH_BYTES);
memcpy(dd->bsev.ivkey_base, eng->ctx->key, eng->ctx->keylen);
+ /* sync the buffer for device */
+ dma_sync_single_for_device(dd->dev, dd->bsev.ivkey_phys_base,
+ eng->ctx->keylen, DMA_TO_DEVICE);
+
/* copy the key table from sdram to vram */
cmdq[0] = 0;
cmdq[0] = UCQOPCODE_MEMDMAVD << ICQBITSHIFT_OPCODE |
@@ -622,12 +626,20 @@ static int tegra_aes_handle_req(struct tegra_aes_engine *eng)
*/
memcpy(eng->buf_in, (u8 *)req->info, AES_BLOCK_SIZE);
+ /* sync the buffer for device */
+ dma_sync_single_for_device(dd->dev, eng->dma_buf_in,
+ AES_HW_DMA_BUFFER_SIZE_BYTES, DMA_TO_DEVICE);
+
ret = aes_start_crypt(eng, (u32)eng->dma_buf_in,
(u32)eng->dma_buf_out, 1, FLAGS_CBC, false);
if (ret < 0) {
dev_err(dd->dev, "aes_start_crypt fail(%d)\n", ret);
goto out;
}
+
+ /* sync the buffer for cpu */
+ dma_sync_single_for_cpu(dd->dev, eng->dma_buf_out,
+ AES_HW_DMA_BUFFER_SIZE_BYTES, DMA_FROM_DEVICE);
}
while (total) {
@@ -960,6 +972,10 @@ static int tegra_aes_get_random(struct crypto_rng *tfm, u8 *rdata,
memset(eng->buf_in, 0, AES_BLOCK_SIZE);
memcpy(eng->buf_in, dt, DEFAULT_RNG_BLK_SZ);
+ /* sync the buffer for device */
+ dma_sync_single_for_device(dd->dev, eng->dma_buf_in,
+ AES_HW_DMA_BUFFER_SIZE_BYTES, DMA_TO_DEVICE);
+
ret = aes_start_crypt(eng, (u32)eng->dma_buf_in, (u32)eng->dma_buf_out,
1, FLAGS_ENCRYPT | FLAGS_RNG, true);
if (ret < 0) {
@@ -967,6 +983,10 @@ static int tegra_aes_get_random(struct crypto_rng *tfm, u8 *rdata,
dlen = ret;
goto out;
}
+ /* sync the buffer for cpu */
+ dma_sync_single_for_cpu(dd->dev, eng->dma_buf_out,
+ AES_HW_DMA_BUFFER_SIZE_BYTES, DMA_FROM_DEVICE);
+
memcpy(dest, eng->buf_out, dlen);
/* update the DT */
@@ -1054,12 +1074,20 @@ static int tegra_aes_rng_reset(struct crypto_rng *tfm, u8 *seed,
/* set seed to the aes hw slot */
memset(eng->buf_in, 0, AES_BLOCK_SIZE);
memcpy(eng->buf_in, seed, DEFAULT_RNG_BLK_SZ);
+
+ /* sync the buffer for device */
+ dma_sync_single_for_device(dd->dev, eng->dma_buf_in,
+ AES_HW_DMA_BUFFER_SIZE_BYTES, DMA_TO_DEVICE);
+
ret = aes_start_crypt(eng, (u32)eng->dma_buf_in,
(u32)eng->dma_buf_out, 1, FLAGS_CBC, false);
if (ret < 0) {
dev_err(dd->dev, "aes_start_crypt fail(%d)\n", ret);
goto out;
}
+ /* sync the buffer for cpu */
+ dma_sync_single_for_cpu(dd->dev, eng->dma_buf_out,
+ AES_HW_DMA_BUFFER_SIZE_BYTES, DMA_FROM_DEVICE);
if (slen >= (2 * DEFAULT_RNG_BLK_SZ + AES_KEYSIZE_128)) {
dt = seed + DEFAULT_RNG_BLK_SZ + AES_KEYSIZE_128;
@@ -1280,14 +1308,14 @@ static int tegra_aes_probe(struct platform_device *pdev)
* - key schedule
*/
dd->bsea.ivkey_base = NULL;
- dd->bsev.ivkey_base = dma_alloc_coherent(dev, AES_MAX_KEY_SIZE,
+ dd->bsev.ivkey_base = dma_alloc_coherent(dev, SZ_512,
&dd->bsev.ivkey_phys_base, GFP_KERNEL);
if (!dd->bsev.ivkey_base) {
dev_err(dev, "can not allocate iv/key buffer for BSEV\n");
err = -ENOMEM;
goto out;
}
- memset(dd->bsev.ivkey_base, 0, AES_MAX_KEY_SIZE);
+ memset(dd->bsev.ivkey_base, 0, SZ_512);
dd->bsev.buf_in = dma_alloc_coherent(dev, AES_HW_DMA_BUFFER_SIZE_BYTES,
&dd->bsev.dma_buf_in, GFP_KERNEL);
diff --git a/drivers/crypto/tegra-se.c b/drivers/crypto/tegra-se.c
index 3d2e9187b949..c03065356984 100644
--- a/drivers/crypto/tegra-se.c
+++ b/drivers/crypto/tegra-se.c
@@ -4,7 +4,7 @@
*
* Support for Tegra Security Engine hardware crypto algorithms.
*
- * Copyright (c) 2011, NVIDIA Corporation.
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -622,9 +622,12 @@ static int tegra_se_count_sgs(struct scatterlist *sl, u32 total_bytes)
return 0;
do {
- total_bytes -= min(sl[i].length, total_bytes);
+ if (!sl->length)
+ return 0;
+ total_bytes -= min(sl->length, total_bytes);
i++;
- } while (total_bytes);
+ sl = sg_next(sl);
+ } while (total_bytes && sl);
return i;
}
@@ -846,7 +849,7 @@ static int tegra_se_aes_queue_req(struct ablkcipher_request *req)
bool idle = true;
int err = 0;
- if (!req->nbytes)
+ if (!tegra_se_count_sgs(req->src, req->nbytes))
return -EINVAL;
spin_lock_irqsave(&se_dev->lock, flags);
@@ -1899,14 +1902,6 @@ static int tegra_se_probe(struct platform_device *pdev)
goto err_irq;
}
- err = request_irq(se_dev->irq, tegra_se_irq, IRQF_DISABLED,
- DRIVER_NAME, se_dev);
- if (err) {
- dev_err(se_dev->dev, "request_irq failed - irq[%d] err[%d]\n",
- se_dev->irq, err);
- goto err_irq;
- }
-
/* Initialize the clock */
se_dev->pclk = clk_get(se_dev->dev, "se");
if (IS_ERR(se_dev->pclk)) {
@@ -1939,6 +1934,14 @@ static int tegra_se_probe(struct platform_device *pdev)
pm_runtime_enable(se_dev->dev);
tegra_se_key_read_disable_all();
+ err = request_irq(se_dev->irq, tegra_se_irq, IRQF_DISABLED,
+ DRIVER_NAME, se_dev);
+ if (err) {
+ dev_err(se_dev->dev, "request_irq failed - irq[%d] err[%d]\n",
+ se_dev->irq, err);
+ goto clean;
+ }
+
err = tegra_se_alloc_ll_buf(se_dev, SE_MAX_SRC_SG_COUNT,
SE_MAX_DST_SG_COUNT);
if (err) {
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index d539efd96d4b..9b304f254f98 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -271,6 +271,15 @@ config GPIO_PCF857X
This driver provides an in-kernel interface to those GPIOs using
platform-neutral GPIO calls.
+config GPIO_RC5T583
+ bool "RICOH RC5T583 GPIO"
+ depends on MFD_RC5T583
+ help
+ Select this option to enable GPIO driver for the Ricoh RC5T583
+ chip family.
+ This driver provides the support for driving/reading the gpio pins
+ of RC5T583 device through standard gpio library.
+
config GPIO_SX150X
bool "Semtech SX150x I2C GPIO expander"
depends on I2C=y
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 9588948c96f0..4ef6785f446b 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -37,6 +37,7 @@ obj-$(CONFIG_GPIO_PCA953X) += gpio-pca953x.o
obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o
obj-$(CONFIG_GPIO_PCH) += gpio-pch.o
obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o
+obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o
obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o
obj-$(CONFIG_GPIO_PLAT_SAMSUNG) += gpio-plat-samsung.o
diff --git a/drivers/gpio/gpio-rc5t583.c b/drivers/gpio/gpio-rc5t583.c
new file mode 100644
index 000000000000..08428bf17718
--- /dev/null
+++ b/drivers/gpio/gpio-rc5t583.c
@@ -0,0 +1,180 @@
+/*
+ * GPIO driver for RICOH583 power management chip.
+ *
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ * Author: Laxman dewangan <ldewangan@nvidia.com>
+ *
+ * Based on code
+ * Copyright (C) 2011 RICOH COMPANY,LTD
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/mfd/rc5t583.h>
+
+struct rc5t583_gpio {
+ struct gpio_chip gpio_chip;
+ struct rc5t583 *rc5t583;
+};
+
+static inline struct rc5t583_gpio *to_rc5t583_gpio(struct gpio_chip *chip)
+{
+ return container_of(chip, struct rc5t583_gpio, gpio_chip);
+}
+
+static int rc5t583_gpio_get(struct gpio_chip *gc, unsigned int offset)
+{
+ struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc);
+ struct device *parent = rc5t583_gpio->rc5t583->dev;
+ uint8_t val = 0;
+ int ret;
+
+ ret = rc5t583_read(parent, RC5T583_GPIO_MON_IOIN, &val);
+ if (ret < 0)
+ return ret;
+
+ return !!(val & BIT(offset));
+}
+
+static void rc5t583_gpio_set(struct gpio_chip *gc, unsigned int offset, int val)
+{
+ struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc);
+ struct device *parent = rc5t583_gpio->rc5t583->dev;
+ if (val)
+ rc5t583_set_bits(parent, RC5T583_GPIO_IOOUT, BIT(offset));
+ else
+ rc5t583_clear_bits(parent, RC5T583_GPIO_IOOUT, BIT(offset));
+}
+
+static int rc5t583_gpio_dir_input(struct gpio_chip *gc, unsigned int offset)
+{
+ struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc);
+ struct device *parent = rc5t583_gpio->rc5t583->dev;
+ int ret;
+
+ ret = rc5t583_clear_bits(parent, RC5T583_GPIO_IOSEL, BIT(offset));
+ if (ret < 0)
+ return ret;
+
+ /* Set pin to gpio mode */
+ return rc5t583_clear_bits(parent, RC5T583_GPIO_PGSEL, BIT(offset));
+}
+
+static int rc5t583_gpio_dir_output(struct gpio_chip *gc, unsigned offset,
+ int value)
+{
+ struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc);
+ struct device *parent = rc5t583_gpio->rc5t583->dev;
+ int ret;
+
+ rc5t583_gpio_set(gc, offset, value);
+ ret = rc5t583_set_bits(parent, RC5T583_GPIO_IOSEL, BIT(offset));
+ if (ret < 0)
+ return ret;
+
+ /* Set pin to gpio mode */
+ return rc5t583_clear_bits(parent, RC5T583_GPIO_PGSEL, BIT(offset));
+}
+
+static int rc5t583_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
+{
+ struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc);
+
+ if ((offset >= 0) && (offset < 8))
+ return rc5t583_gpio->rc5t583->irq_base +
+ RC5T583_IRQ_GPIO0 + offset;
+ return -EINVAL;
+}
+
+static void rc5t583_gpio_free(struct gpio_chip *gc, unsigned offset)
+{
+ struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc);
+ struct device *parent = rc5t583_gpio->rc5t583->dev;
+
+ rc5t583_set_bits(parent, RC5T583_GPIO_PGSEL, BIT(offset));
+}
+
+static int __devinit rc5t583_gpio_probe(struct platform_device *pdev)
+{
+ struct rc5t583 *rc5t583 = dev_get_drvdata(pdev->dev.parent);
+ struct rc5t583_platform_data *pdata = dev_get_platdata(rc5t583->dev);
+ struct rc5t583_gpio *rc5t583_gpio;
+
+ rc5t583_gpio = devm_kzalloc(&pdev->dev, sizeof(*rc5t583_gpio),
+ GFP_KERNEL);
+ if (!rc5t583_gpio) {
+ dev_warn(&pdev->dev, "Mem allocation for rc5t583_gpio failed");
+ return -ENOMEM;
+ }
+
+ rc5t583_gpio->gpio_chip.label = "gpio-rc5t583",
+ rc5t583_gpio->gpio_chip.owner = THIS_MODULE,
+ rc5t583_gpio->gpio_chip.free = rc5t583_gpio_free,
+ rc5t583_gpio->gpio_chip.direction_input = rc5t583_gpio_dir_input,
+ rc5t583_gpio->gpio_chip.direction_output = rc5t583_gpio_dir_output,
+ rc5t583_gpio->gpio_chip.set = rc5t583_gpio_set,
+ rc5t583_gpio->gpio_chip.get = rc5t583_gpio_get,
+ rc5t583_gpio->gpio_chip.to_irq = rc5t583_gpio_to_irq,
+ rc5t583_gpio->gpio_chip.ngpio = RC5T583_MAX_GPIO,
+ rc5t583_gpio->gpio_chip.can_sleep = 1,
+ rc5t583_gpio->gpio_chip.dev = &pdev->dev;
+ rc5t583_gpio->gpio_chip.base = -1;
+ rc5t583_gpio->rc5t583 = rc5t583;
+
+ if (pdata && pdata->gpio_base)
+ rc5t583_gpio->gpio_chip.base = pdata->gpio_base;
+
+ platform_set_drvdata(pdev, rc5t583_gpio);
+
+ return gpiochip_add(&rc5t583_gpio->gpio_chip);
+}
+
+static int __devexit rc5t583_gpio_remove(struct platform_device *pdev)
+{
+ struct rc5t583_gpio *rc5t583_gpio = platform_get_drvdata(pdev);
+
+ return gpiochip_remove(&rc5t583_gpio->gpio_chip);
+}
+
+static struct platform_driver rc5t583_gpio_driver = {
+ .driver = {
+ .name = "rc5t583-gpio",
+ .owner = THIS_MODULE,
+ },
+ .probe = rc5t583_gpio_probe,
+ .remove = __devexit_p(rc5t583_gpio_remove),
+};
+
+static int __init rc5t583_gpio_init(void)
+{
+ return platform_driver_register(&rc5t583_gpio_driver);
+}
+subsys_initcall(rc5t583_gpio_init);
+
+static void __exit rc5t583_gpio_exit(void)
+{
+ platform_driver_unregister(&rc5t583_gpio_driver);
+}
+module_exit(rc5t583_gpio_exit);
+
+MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
+MODULE_DESCRIPTION("GPIO interface for RC5T583");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:rc5t583-gpio");
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index 3a0893f9cdc3..49abdf016b26 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -32,6 +32,7 @@
#include <asm/mach/irq.h>
#include <mach/iomap.h>
+#include <mach/legacy_irq.h>
#include <mach/pinmux.h>
#include "../../../arch/arm/mach-tegra/pm-irq.h"
@@ -90,6 +91,7 @@ struct tegra_gpio_bank {
u32 oe[4];
u32 int_enb[4];
u32 int_lvl[4];
+ u32 wake_enb[4];
#endif
};
@@ -191,6 +193,7 @@ static int tegra_gpio_get(struct gpio_chip *chip, unsigned offset)
static int tegra_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
tegra_gpio_mask_write(GPIO_MSK_OE(offset), offset, 0);
+ tegra_gpio_enable(offset);
return 0;
}
@@ -199,6 +202,7 @@ static int tegra_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
{
tegra_gpio_set(chip, offset, value);
tegra_gpio_mask_write(GPIO_MSK_OE(offset), offset, 1);
+ tegra_gpio_enable(offset);
return 0;
}
@@ -213,8 +217,20 @@ static int tegra_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
return TEGRA_GPIO_TO_IRQ(offset);
}
+static int tegra_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ return 0;
+}
+
+static void tegra_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ tegra_gpio_disable(offset);
+}
+
static struct gpio_chip tegra_gpio_chip = {
.label = "tegra-gpio",
+ .request = tegra_gpio_request,
+ .free = tegra_gpio_free,
.direction_input = tegra_gpio_direction_input,
.get = tegra_gpio_get,
.direction_output = tegra_gpio_direction_output,
@@ -381,21 +397,60 @@ static int tegra_gpio_suspend(void)
return 0;
}
+static int tegra_update_lp1_gpio_wake(struct irq_data *d, bool enable)
+{
+#ifdef CONFIG_PM_SLEEP
+ struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
+ u8 mask;
+ u8 port_index;
+ u8 pin_index_in_bank;
+ u8 pin_in_port;
+ int gpio = d->irq - INT_GPIO_BASE;
+
+ if (gpio < 0)
+ return -EIO;
+ pin_index_in_bank = (gpio & 0x1F);
+ port_index = pin_index_in_bank >> 3;
+ pin_in_port = (pin_index_in_bank & 0x7);
+ mask = BIT(pin_in_port);
+ if (enable)
+ bank->wake_enb[port_index] |= mask;
+ else
+ bank->wake_enb[port_index] &= ~mask;
+#endif
+
+ return 0;
+}
+
static int tegra_gpio_irq_set_wake(struct irq_data *d, unsigned int enable)
{
struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
int ret = 0;
- ret = tegra_pm_irq_set_wake(d->irq, enable);
+ /*
+ * update LP1 mask for gpio port/pin interrupt
+ * LP1 enable independent of LP0 wake support
+ */
+ ret = tegra_update_lp1_gpio_wake(d, enable);
+ if (ret) {
+ pr_err("Failed gpio lp1 %s for irq=%d, error=%d\n",
+ (enable ? "enable" : "disable"), d->irq, ret);
+ goto fail;
+ }
+ /* LP1 enable for bank interrupt */
+ ret = tegra_update_lp1_irq_wake(bank->irq, enable);
if (ret)
- return ret;
-
- ret = irq_set_irq_wake(bank->irq, enable);
+ pr_err("Failed gpio lp1 %s for irq=%d, error=%d\n",
+ (enable ? "enable" : "disable"), bank->irq, ret);
+ /* LP0 */
+ ret = tegra_pm_irq_set_wake(d->irq, enable);
if (ret)
- tegra_pm_irq_set_wake(d->irq, !enable);
+ pr_err("Failed gpio lp0 %s for irq=%d, error=%d\n",
+ (enable ? "enable" : "disable"), d->irq, ret);
+fail:
return ret;
}
#else
diff --git a/drivers/gpio/gpio-tps65910.c b/drivers/gpio/gpio-tps65910.c
index 7eef648a3351..af6dc837ffca 100644
--- a/drivers/gpio/gpio-tps65910.c
+++ b/drivers/gpio/gpio-tps65910.c
@@ -18,14 +18,26 @@
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
+#include <linux/platform_device.h>
#include <linux/mfd/tps65910.h>
+struct tps65910_gpio {
+ struct gpio_chip gpio_chip;
+ struct tps65910 *tps65910;
+};
+
+static inline struct tps65910_gpio *to_tps65910_gpio(struct gpio_chip *chip)
+{
+ return container_of(chip, struct tps65910_gpio, gpio_chip);
+}
+
static int tps65910_gpio_get(struct gpio_chip *gc, unsigned offset)
{
- struct tps65910 *tps65910 = container_of(gc, struct tps65910, gpio);
- uint8_t val;
+ struct tps65910_gpio *tps65910_gpio = to_tps65910_gpio(gc);
+ struct tps65910 *tps65910 = tps65910_gpio->tps65910;
+ unsigned int val;
- tps65910->read(tps65910, TPS65910_GPIO0 + offset, 1, &val);
+ tps65910_reg_read(tps65910, TPS65910_GPIO0 + offset, &val);
if (val & GPIO_STS_MASK)
return 1;
@@ -36,83 +48,135 @@ static int tps65910_gpio_get(struct gpio_chip *gc, unsigned offset)
static void tps65910_gpio_set(struct gpio_chip *gc, unsigned offset,
int value)
{
- struct tps65910 *tps65910 = container_of(gc, struct tps65910, gpio);
+ struct tps65910_gpio *tps65910_gpio = to_tps65910_gpio(gc);
+ struct tps65910 *tps65910 = tps65910_gpio->tps65910;
if (value)
- tps65910_set_bits(tps65910, TPS65910_GPIO0 + offset,
+ tps65910_reg_set_bits(tps65910, TPS65910_GPIO0 + offset,
GPIO_SET_MASK);
else
- tps65910_clear_bits(tps65910, TPS65910_GPIO0 + offset,
+ tps65910_reg_clear_bits(tps65910, TPS65910_GPIO0 + offset,
GPIO_SET_MASK);
}
static int tps65910_gpio_output(struct gpio_chip *gc, unsigned offset,
int value)
{
- struct tps65910 *tps65910 = container_of(gc, struct tps65910, gpio);
+ struct tps65910_gpio *tps65910_gpio = to_tps65910_gpio(gc);
+ struct tps65910 *tps65910 = tps65910_gpio->tps65910;
/* Set the initial value */
tps65910_gpio_set(gc, offset, value);
- return tps65910_set_bits(tps65910, TPS65910_GPIO0 + offset,
+ return tps65910_reg_set_bits(tps65910, TPS65910_GPIO0 + offset,
GPIO_CFG_MASK);
}
static int tps65910_gpio_input(struct gpio_chip *gc, unsigned offset)
{
- struct tps65910 *tps65910 = container_of(gc, struct tps65910, gpio);
+ struct tps65910_gpio *tps65910_gpio = to_tps65910_gpio(gc);
+ struct tps65910 *tps65910 = tps65910_gpio->tps65910;
- return tps65910_clear_bits(tps65910, TPS65910_GPIO0 + offset,
+ return tps65910_reg_clear_bits(tps65910, TPS65910_GPIO0 + offset,
GPIO_CFG_MASK);
}
-void tps65910_gpio_init(struct tps65910 *tps65910, int gpio_base)
+static int __devinit tps65910_gpio_probe(struct platform_device *pdev)
{
+ struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent);
+ struct tps65910_board *pdata = dev_get_platdata(tps65910->dev);
+ struct tps65910_gpio *tps65910_gpio;
int ret;
- struct tps65910_board *board_data;
+ int i;
+
+ tps65910_gpio = devm_kzalloc(&pdev->dev,
+ sizeof(*tps65910_gpio), GFP_KERNEL);
+ if (!tps65910_gpio) {
+ dev_err(&pdev->dev, "Could not allocate tps65910_gpio\n");
+ return -ENOMEM;
+ }
- if (!gpio_base)
- return;
+ tps65910_gpio->tps65910 = tps65910;
- tps65910->gpio.owner = THIS_MODULE;
- tps65910->gpio.label = tps65910->i2c_client->name;
- tps65910->gpio.dev = tps65910->dev;
- tps65910->gpio.base = gpio_base;
+ tps65910_gpio->gpio_chip.owner = THIS_MODULE;
+ tps65910_gpio->gpio_chip.label = tps65910->i2c_client->name;
switch(tps65910_chip_id(tps65910)) {
case TPS65910:
- tps65910->gpio.ngpio = TPS65910_NUM_GPIO;
+ tps65910_gpio->gpio_chip.ngpio = TPS65910_NUM_GPIO;
break;
case TPS65911:
- tps65910->gpio.ngpio = TPS65911_NUM_GPIO;
+ tps65910_gpio->gpio_chip.ngpio = TPS65911_NUM_GPIO;
break;
default:
- return;
+ return -EINVAL;
}
- tps65910->gpio.can_sleep = 1;
-
- tps65910->gpio.direction_input = tps65910_gpio_input;
- tps65910->gpio.direction_output = tps65910_gpio_output;
- tps65910->gpio.set = tps65910_gpio_set;
- tps65910->gpio.get = tps65910_gpio_get;
-
- /* Configure sleep control for gpios */
- board_data = dev_get_platdata(tps65910->dev);
- if (board_data) {
- int i;
- for (i = 0; i < tps65910->gpio.ngpio; ++i) {
- if (board_data->en_gpio_sleep[i]) {
- ret = tps65910_set_bits(tps65910,
- TPS65910_GPIO0 + i, GPIO_SLEEP_MASK);
- if (ret < 0)
- dev_warn(tps65910->dev,
- "GPIO Sleep setting failed\n");
- }
- }
+ tps65910_gpio->gpio_chip.can_sleep = 1;
+ tps65910_gpio->gpio_chip.direction_input = tps65910_gpio_input;
+ tps65910_gpio->gpio_chip.direction_output = tps65910_gpio_output;
+ tps65910_gpio->gpio_chip.set = tps65910_gpio_set;
+ tps65910_gpio->gpio_chip.get = tps65910_gpio_get;
+ tps65910_gpio->gpio_chip.dev = &pdev->dev;
+ if (pdata && pdata->gpio_base)
+ tps65910_gpio->gpio_chip.base = pdata->gpio_base;
+ else
+ tps65910_gpio->gpio_chip.base = -1;
+
+ if (!pdata)
+ goto skip_init;
+
+ /* Configure sleep control for gpios if provided */
+ for (i = 0; i < tps65910_gpio->gpio_chip.ngpio; ++i) {
+ if (!pdata->en_gpio_sleep[i])
+ continue;
+
+ ret = tps65910_reg_set_bits(tps65910,
+ TPS65910_GPIO0 + i, GPIO_SLEEP_MASK);
+ if (ret < 0)
+ dev_warn(tps65910->dev,
+ "GPIO Sleep setting failed with err %d\n", ret);
+ }
+
+skip_init:
+ ret = gpiochip_add(&tps65910_gpio->gpio_chip);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
+ return ret;
}
- ret = gpiochip_add(&tps65910->gpio);
+ platform_set_drvdata(pdev, tps65910_gpio);
- if (ret)
- dev_warn(tps65910->dev, "GPIO registration failed: %d\n", ret);
+ return ret;
}
+
+static int __devexit tps65910_gpio_remove(struct platform_device *pdev)
+{
+ struct tps65910_gpio *tps65910_gpio = platform_get_drvdata(pdev);
+
+ return gpiochip_remove(&tps65910_gpio->gpio_chip);
+}
+
+static struct platform_driver tps65910_gpio_driver = {
+ .driver.name = "tps65910-gpio",
+ .driver.owner = THIS_MODULE,
+ .probe = tps65910_gpio_probe,
+ .remove = __devexit_p(tps65910_gpio_remove),
+};
+
+static int __init tps65910_gpio_init(void)
+{
+ return platform_driver_register(&tps65910_gpio_driver);
+}
+subsys_initcall(tps65910_gpio_init);
+
+static void __exit tps65910_gpio_exit(void)
+{
+ platform_driver_unregister(&tps65910_gpio_driver);
+}
+module_exit(tps65910_gpio_exit);
+
+MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>");
+MODULE_AUTHOR("Jorge Eduardo Candelaria jedu@slimlogic.co.uk>");
+MODULE_DESCRIPTION("GPIO interface for TPS65910/TPS6511 PMICs");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:tps65910-gpio");
diff --git a/drivers/gpu/ion/tegra/Makefile b/drivers/gpu/ion/tegra/Makefile
index 11cd003fb08f..0fe898c6ee49 100644
--- a/drivers/gpu/ion/tegra/Makefile
+++ b/drivers/gpu/ion/tegra/Makefile
@@ -1 +1,3 @@
+subdir-ccflags-y := -Werror
+
obj-y += tegra_ion.o
diff --git a/drivers/gpu/ion/tegra/tegra_ion.c b/drivers/gpu/ion/tegra/tegra_ion.c
index 2252079279e8..e929ec84fc53 100644
--- a/drivers/gpu/ion/tegra/tegra_ion.c
+++ b/drivers/gpu/ion/tegra/tegra_ion.c
@@ -31,7 +31,7 @@
#define HEAP_FLAGS 0xFF
#if !defined(CONFIG_TEGRA_NVMAP)
-#include "mach/nvmap.h"
+#include "linux/nvmap.h"
struct nvmap_device *nvmap_dev;
#endif
diff --git a/drivers/hwmon/tegra-tsensor.c b/drivers/hwmon/tegra-tsensor.c
index 28597ef4cc98..1c372a4bcce5 100644
--- a/drivers/hwmon/tegra-tsensor.c
+++ b/drivers/hwmon/tegra-tsensor.c
@@ -97,13 +97,20 @@
#define TSENSOR_SLOWDOWN_BIT 23
/* macros used for temperature calculations */
-#define get_temperature_int(X) ((X) / 100)
-#define get_temperature_fraction(X) (((int)(abs(X))) % 100)
-#define get_temperature_round(X) DIV_ROUND_CLOSEST(X, 100)
+/* assumed get_temperature_int and get_temperature_fraction
+ * calculate up to 6 decimal places. print temperature
+ * in code assumes 6 decimal place formatting */
+#define get_temperature_int(X) ((X) / 1000000)
+#define get_temperature_fraction(X) (((int)(abs(X))) % 1000000)
+
+#define get_temperature_round(X) DIV_ROUND_CLOSEST(X, 1000000)
#define MILLICELSIUS_TO_CELSIUS(i) ((i) / 1000)
#define CELSIUS_TO_MILLICELSIUS(i) ((i) * 1000)
+#define TSENSOR_MILLI_CELSIUS(x) \
+ DIV_ROUND_CLOSEST((x), 1000)
+
#define get_ts_state(data) tsensor_get_reg_field(data,\
((data->instance << 16) | SENSOR_STATUS0), \
STATUS0_STATE_SHIFT, STATE_MASK)
@@ -188,8 +195,8 @@ struct tegra_tsensor_data {
unsigned int config2[TSENSOR_COUNT];
/* temperature readings from instance tsensor - 0/1 */
unsigned int instance;
- int A_e_minus6;
- int B_e_minus2;
+ s64 A_e_minus12;
+ int B_e_minus6;
unsigned int fuse_T1;
unsigned int fuse_F1;
unsigned int fuse_T2;
@@ -353,6 +360,8 @@ static void get_chip_tsensor_coeff(struct tegra_tsensor_data *data)
data->m_e_minus6 = coeff_table[coeff_index].e_minus6_m;
data->n_e_minus6 = coeff_table[coeff_index].e_minus6_n;
data->p_e_minus2 = coeff_table[coeff_index].e_minus2_p;
+ pr_info("tsensor coeff: m=%d*10^-6,n=%d*10^-6,p=%d*10^-2\n",
+ data->m_e_minus6, data->n_e_minus6, data->p_e_minus2);
}
/* tsensor counter read function */
@@ -480,9 +489,10 @@ static ssize_t tsensor_show_counters(struct device *dev,
snprintf(buf, (((LOCAL_STR_SIZE1 << 1) + 3) +
strlen(fixed_str)),
- "%d.%02dC\n",
+ "%d.%06dC %#x\n",
get_temperature_int(temp),
- get_temperature_fraction(temp));
+ get_temperature_fraction(temp),
+ ((curr_avg & 0xFFFF0000) >> 16));
}
return strlen(buf);
error:
@@ -567,8 +577,8 @@ static ssize_t show_tsensor_param(struct device *dev,
err = tsensor_count_2_temp(data, val, &temp);
if (err != 0)
goto labelErr;
- snprintf(buf, PAGE_SIZE, "%s threshold: %d.%d Celsius\n", info,
- get_temperature_int(temp),
+ snprintf(buf, PAGE_SIZE, "%s threshold: %d.%06d Celsius\n",
+ info, get_temperature_int(temp),
get_temperature_fraction(temp));
}
return strlen(buf);
@@ -644,7 +654,7 @@ int tsensor_thermal_get_temp_low(struct tegra_tsensor_data *data,
long *milli_temp)
{
/* temp to counter below 20C seems to be inaccurate */
- *milli_temp = 20000;
+ *milli_temp = 0;
return 0;
}
@@ -660,7 +670,8 @@ int tsensor_thermal_get_temp(struct tegra_tsensor_data *data,
if (err)
return err;
- temp *= 10;
+ /* temperature is in milli-Celsius */
+ temp = TSENSOR_MILLI_CELSIUS(temp);
mutex_lock(&data->mutex);
@@ -787,8 +798,9 @@ static int read_tsensor_fuse_regs(struct tegra_tsensor_data *data)
*/
dev_vdbg(data->hwmon_dev, "Tsensor low temp (T2) fuse :\n");
T2 = (spare_bits & 0x7F) | ((spare_bits >> 7) & 0x7F);
- pr_info("Tsensor fuse calibration F1=%d, F2=%d, T1=%d, T2=%d\n"
- , data->fuse_F1, data->fuse_F2, T1, T2);
+ pr_info("Tsensor fuse calibration F1=%d(%#x), F2=%d(%#x), T1=%d, T2=%d\n",
+ data->fuse_F1, data->fuse_F1,
+ data->fuse_F2, data->fuse_F2, T1, T2);
data->fuse_T1 = T1;
data->fuse_T2 = T2;
return 0;
@@ -798,9 +810,14 @@ errLabel:
/* function to calculate interim temperature */
static int calc_interim_temp(struct tegra_tsensor_data *data,
- unsigned int counter, int *p_interim_temp)
+ unsigned int counter, s64 *p_interim_temp)
{
- int val1;
+ s64 val1_64;
+ s64 val2;
+ u32 temp_rem;
+ bool is_neg;
+ u32 divisor;
+
/*
* T-int = A * Counter + B
* (Counter is the sensor frequency output)
@@ -817,14 +834,27 @@ static int calc_interim_temp(struct tegra_tsensor_data *data,
* s_B is 10^2 times and want end result to be 10^2 times
* actual value
*/
- val1 = DIV_ROUND_CLOSEST((data->A_e_minus6 * counter) , 10000);
- dev_vdbg(data->hwmon_dev, "A*counter / 100 = %d\n",
- val1);
- *p_interim_temp = (val1 + data->B_e_minus2);
+ val1_64 = (data->A_e_minus12 * counter);
+ dev_dbg(data->hwmon_dev, "A_e_-12*counter=%lld\n", val1_64);
+ val2 = (s64)data->B_e_minus6 * 1000000ULL;
+ dev_dbg(data->hwmon_dev, "B_e_-12=%lld\n", val2);
+ val2 += val1_64;
+ dev_dbg(data->hwmon_dev, "A_counter+B=%lld\n", val2);
+ is_neg = false;
+ if (val2 < 0) {
+ is_neg = true;
+ val2 *= -1;
+ }
+ divisor = 1000000;
+ temp_rem = do_div(val2, divisor);
+ if (temp_rem > (divisor >> 1))
+ val2++;
+ if (is_neg)
+ val2 *= -1;
+ *p_interim_temp = val2;
+ dev_dbg(data->hwmon_dev, "counter=%d, interim_temp=%lld\n",
+ counter, *p_interim_temp);
}
- dev_dbg(data->hwmon_dev, "tsensor: counter=0x%x, interim "
- "temp*100=%d\n",
- counter, *p_interim_temp);
return 0;
}
@@ -833,9 +863,13 @@ static int calc_interim_temp(struct tegra_tsensor_data *data,
* interim temperature
*/
static void calc_final_temp(struct tegra_tsensor_data *data,
- int interim_temp, int *p_final_temp)
+ s64 interim_temp, int *p_final_temp)
{
- int temp1, temp2, temp;
+ s64 temp1_64, temp2_64, temp_64, temp1_64_rem;
+ u32 temp_rem_32;
+ u32 divisor;
+ u64 divisor_64;
+ bool is_neg;
/*
* T-final = m * T-int ^2 + n * T-int + p
* m = -0.002775
@@ -843,34 +877,51 @@ static void calc_final_temp(struct tegra_tsensor_data *data,
* p = -7.3
*/
- dev_vdbg(data->hwmon_dev, "interim_temp=%d\n", interim_temp);
- temp1 = (DIV_ROUND_CLOSEST((interim_temp * interim_temp) , 100));
- dev_vdbg(data->hwmon_dev, "temp1=%d\n", temp1);
- temp1 *= (DIV_ROUND_CLOSEST(data->m_e_minus6 , 10));
- dev_vdbg(data->hwmon_dev, "m*T-int^2=%d\n", temp1);
- temp1 = (DIV_ROUND_CLOSEST(temp1, 10000));
- /* we want to keep 3 decimal point digits */
- dev_vdbg(data->hwmon_dev, "m*T-int^2 / 10000=%d\n", temp1);
- dev_dbg(data->hwmon_dev, "temp1*100=%d\n", temp1);
-
- temp2 = (DIV_ROUND_CLOSEST(interim_temp * (
- DIV_ROUND_CLOSEST(data->n_e_minus6, 100)
- ), 1000)); /* 1000 times actual */
- dev_vdbg(data->hwmon_dev, "n*T-int =%d\n", temp2);
-
- temp = temp1 + temp2;
- dev_vdbg(data->hwmon_dev, "m*T-int^2 + n*T-int =%d\n", temp);
- temp += (data->p_e_minus2 * 10);
- temp = DIV_ROUND_CLOSEST(temp, 10);
- /* final temperature(temp) is 100 times actual value
- * to preserve 2 decimal digits and enable fixed point
- * computation
- */
- dev_vdbg(data->hwmon_dev, "m*T-int^2 + n*T-int + p =%d\n",
- temp);
- dev_dbg(data->hwmon_dev, "Final temp=%d.%d\n",
- get_temperature_int(temp), get_temperature_fraction(temp));
- *p_final_temp = (int)(temp);
+ temp1_64 = (interim_temp * interim_temp);
+ /* always positive as squaring value */
+ /* losing accuracy here */
+ divisor = 10000;
+ /* temp1_64 contains quotient and returns remainder */
+ temp_rem_32 = do_div(temp1_64, divisor);
+ if (temp_rem_32 > (divisor >> 1))
+ temp1_64++;
+ temp1_64 *= (s64)data->m_e_minus6;
+ dev_dbg(data->hwmon_dev, "m_T-interim^2_e^14=%lld\n", temp1_64);
+ temp1_64_rem = (s64)data->m_e_minus6 * (s64)temp_rem_32;
+ is_neg = false;
+ if (temp1_64_rem < 0) {
+ is_neg = true;
+ temp1_64_rem *= -1;
+ }
+ temp_rem_32 = do_div(temp1_64_rem, divisor);
+ if (temp_rem_32 > (divisor >> 1))
+ temp1_64_rem++;
+ if (is_neg)
+ temp1_64_rem *= -1;
+ /* temp1_64 is m * t-int * t-int * 10^14 */
+
+ temp2_64 = (s64)data->n_e_minus6 * interim_temp * 100;
+ dev_dbg(data->hwmon_dev, "n_T-interim_e^14=%lld\n", temp2_64);
+ /* temp2_64 is n * t-int * 10^14 */
+
+ temp_64 = ((s64)data->p_e_minus2 * (s64)1000000000000ULL);
+ /* temp_64 is n * 10^14 */
+ temp_64 += temp1_64 + temp2_64 + temp1_64_rem;
+ is_neg = false;
+ if (temp_64 < 0) {
+ is_neg = true;
+ temp_64 *= -1;
+ }
+ divisor_64 = 100000000ULL;
+ temp_rem_32 = do_div(temp_64, divisor_64);
+ if (temp_rem_32 > (divisor_64 >> 1))
+ temp_64++;
+ if (is_neg)
+ temp_64 *= -1;
+ /* temperature * 10^14 / 10^8 */
+ /* get LS decimal digit rounding */
+ *p_final_temp = (s32)temp_64;
+ dev_dbg(data->hwmon_dev, "T-final stage4=%d\n", *p_final_temp);
}
/*
@@ -882,6 +933,10 @@ static void calc_final_temp(struct tegra_tsensor_data *data,
static int tsensor_get_const_AB(struct tegra_tsensor_data *data)
{
int err;
+ s64 temp_val1, temp_val2;
+ u32 temp_rem;
+ bool is_neg;
+ u32 divisor;
/*
* 1. Find fusing registers for 25C (T1, F1) and 90C (T2, F2);
@@ -902,17 +957,31 @@ static int tsensor_get_const_AB(struct tegra_tsensor_data *data)
"computation\n", data->fuse_F2, data->fuse_F1);
return -EINVAL;
} else {
- data->A_e_minus6 = ((data->fuse_T2 - data->fuse_T1) *
- 1000000);
- data->A_e_minus6 /= (data->fuse_F2 - data->fuse_F1);
- data->B_e_minus2 = (data->fuse_T1 * 100) - (
- DIV_ROUND_CLOSEST((data->A_e_minus6 *
- data->fuse_F1), 10000));
- /* B is 100 times now */
+ temp_val1 = (s64)(data->fuse_T2 - data->fuse_T1) *
+ 1000000000000ULL;
+ /* temp_val1 always positive as fuse_T2 > fuse_T1 */
+ temp_rem = do_div(temp_val1, (data->fuse_F2 -
+ data->fuse_F1));
+ data->A_e_minus12 = temp_val1;
+ temp_val2 = (s64)(data->fuse_T1 * 1000000000000ULL);
+ temp_val2 -= (data->A_e_minus12 * data->fuse_F1);
+ is_neg = false;
+ if (temp_val2 < 0) {
+ is_neg = true;
+ temp_val2 *= -1;
+ }
+ divisor = 1000000;
+ temp_rem = do_div(temp_val2, divisor);
+ if (temp_rem > (divisor >> 1))
+ temp_val2++;
+ if (is_neg)
+ temp_val2 *= -1;
+ data->B_e_minus6 = (s32)temp_val2;
+ /* B is 10^6 times now */
}
}
- dev_dbg(data->hwmon_dev, "A_e_minus6 = %d\n", data->A_e_minus6);
- dev_dbg(data->hwmon_dev, "B_e_minus2 = %d\n", data->B_e_minus2);
+ dev_info(data->hwmon_dev, "A_e_minus12 = %lld\n", data->A_e_minus12);
+ dev_info(data->hwmon_dev, "B_e_minus6 = %d\n", data->B_e_minus6);
return 0;
}
@@ -925,7 +994,7 @@ static int tsensor_get_const_AB(struct tegra_tsensor_data *data)
static int tsensor_count_2_temp(struct tegra_tsensor_data *data,
unsigned int count, int *p_temperature)
{
- int interim_temp;
+ s64 interim_temp;
int err;
/*
@@ -944,28 +1013,16 @@ static int tsensor_count_2_temp(struct tegra_tsensor_data *data,
* 3. Calculate final temperature:
*/
calc_final_temp(data, interim_temp, p_temperature);
+ /* logs counter -> temperature conversion */
+ dev_dbg(data->hwmon_dev, "tsensor: counter=0x%x, interim "
+ "temp*10^6=%lld, Final temp=%d.%06d\n",
+ count, interim_temp,
+ get_temperature_int(*p_temperature),
+ get_temperature_fraction(*p_temperature));
return 0;
}
/*
- * utility function implements ceil to power of 10 -
- * e.g. given 987 it returns 1000
- */
-static int my_ceil_pow10(int num)
-{
- int tmp;
- int val = 1;
- tmp = (num < 0) ? -num : num;
- if (tmp == 0)
- return 0;
- while (tmp > 1) {
- val *= 10;
- tmp /= 10;
- }
- return val;
-}
-
-/*
* function to solve quadratic roots of equation
* used to get counter corresponding to given temperature
*/
@@ -973,104 +1030,140 @@ static void get_quadratic_roots(struct tegra_tsensor_data *data,
int temp, unsigned int *p_counter1,
unsigned int *p_counter2)
{
- /* expr1 = 2 * m * B + n */
- int expr1_e_minus6;
- /* expr2 = expr1^2 */
- int expr2_e_minus6;
- /* expr3 = m * B^2 + n * B + p */
- int expr3_e_minus4_1;
- int expr3_e_minus4_2;
- int expr3_e_minus4;
- int expr4_e_minus6;
- int expr4_e_minus2_1;
- int expr4_e_minus6_2;
- int expr4_e_minus6_3;
- int expr5_e_minus6, expr5_e_minus6_1, expr6, expr7;
- int expr8_e_minus6, expr9_e_minus6;
- int multiplier;
- const int multiplier2 = 1000000;
- int expr10_e_minus6, expr11_e_minus6;
- int expr12, expr13;
-
- dev_vdbg(data->hwmon_dev, "A_e_minus6=%d, B_e_minus2=%d, "
+ /*
+ * Equation to solve:
+ * m * A^2 * Counter^2 +
+ * A * (2 * m * B + n) * Counter +
+ * (m * B^2 + n * B + p - Temperature) = 0
+
+ To calculate root - assume
+ b = A * (2 * m * B + n)
+ a = m * A^2
+ c = ((m * B^2) + n * B + p - temp)
+ root1 = (-b + sqrt(b^2 - (4*a*c))) / (2 * a)
+ root2 = (-b - sqrt(b^2 - (4*a*c))) / (2 * a)
+ sqrt(k) = sqrt(k * 10^6) / sqrt(10^6)
+
+ Roots are :
+ (-(2*m*B+n)+sqrt(((2*m*B+n)^2-4*m(m*B^2+n*B+p-temp))))/(2*m*A)
+ and
+ (-(2*m*B+n)-sqrt(((2*m*B+n)^2-4*m(m*B^2+n*B+p-temp))))/(2*m*A)
+
+ */
+
+ int v_e_minus6_2mB_n;
+ int v_e_minus4_mB2_nB_p_minusTemp;
+ int v_e_minus6_b2, v_e_minus6_4ac;
+ int v_e_minus6_b2_minus4ac;
+ int v_e_minus6_sqrt_b2_minus4ac;
+ s64 v_e_minus12_2mA;
+ int root1, root2;
+ int temp_rem;
+ bool is_neg;
+ s64 temp_64;
+
+ dev_dbg(data->hwmon_dev, "m_e-6=%d,n_e-6=%d,p_e-2=%d,A_e-6=%lld,"
+ "B_e-2=%d\n", data->m_e_minus6, data->n_e_minus6,
+ data->p_e_minus2, data->A_e_minus12, data->B_e_minus6);
+
+ temp_64 = (2ULL * (s64)data->m_e_minus6 * (s64)data->B_e_minus6);
+ is_neg = false;
+ if (temp_64 < 0) {
+ is_neg = true;
+ temp_64 *= -1;
+ }
+ temp_rem = do_div(temp_64, 1000000);
+ if (is_neg)
+ temp_64 *= -1;
+ v_e_minus6_2mB_n = (s32)temp_64 + data->n_e_minus6;
+ /* computed 2mB + n */
+
+ temp_64 = ((s64)data->m_e_minus6 * (s64)data->A_e_minus12);
+ temp_64 *= 2;
+ is_neg = false;
+ if (temp_64 < 0) {
+ temp_64 *= -1;
+ is_neg = true;
+ }
+ temp_rem = do_div(temp_64, 1000000);
+ if (is_neg)
+ temp_64 *= -1;
+ v_e_minus12_2mA = temp_64;
+ /* computed 2mA */
+
+ /* m * B^2 calculation */
+ temp_64 = ((s64)data->B_e_minus6 * (s64)data->B_e_minus6);
+ /* squaring give positive value */
+ temp_rem = do_div(temp_64, 1000000);
+ /* we see overflow if do not divide above */
+ temp_64 *= data->m_e_minus6;
+ is_neg = false;
+ if (temp_64 < 0) {
+ is_neg = true;
+ temp_64 *= -1;
+ }
+ temp_rem = do_div(temp_64, 1000000);
+ temp_rem = do_div(temp_64, 100);
+ if (is_neg)
+ temp_64 *= -1;
+ v_e_minus4_mB2_nB_p_minusTemp = (s32)temp_64;
+
+ /* n * B calculation */
+ temp_64 = ((s64)data->B_e_minus6 * (s64)data->n_e_minus6);
+ is_neg = false;
+ if (temp_64 < 0) {
+ is_neg = true;
+ temp_64 *= -1;
+ }
+ temp_rem = do_div(temp_64, 1000000);
+ temp_rem = do_div(temp_64, 100);
+ if (is_neg)
+ temp_64 *= -1;
+ temp_rem = (s32)temp_64;
+ v_e_minus4_mB2_nB_p_minusTemp += temp_rem;
+ v_e_minus4_mB2_nB_p_minusTemp += (
+ (data->p_e_minus2 * 100) - (temp * 10000));
+ /* computed ((m * B^2) + n * B + p - temp) * 10^4 */
+
+ v_e_minus6_b2 = ((v_e_minus6_2mB_n / 1000)
+ * (v_e_minus6_2mB_n / 1000));
+ dev_dbg(data->hwmon_dev, "v_e_minus6_b2=%d\n", v_e_minus6_b2);
+
+ v_e_minus6_4ac = ((4 * data->m_e_minus6) / 10)
+ * ((v_e_minus4_mB2_nB_p_minusTemp) / 1000);
+ dev_dbg(data->hwmon_dev, "v_e_minus6_4ac=%d\n", v_e_minus6_4ac);
+
+ v_e_minus6_b2_minus4ac = (v_e_minus6_b2 - v_e_minus6_4ac);
+
+ v_e_minus6_sqrt_b2_minus4ac = DIV_ROUND_CLOSEST(
+ (int_sqrt(v_e_minus6_b2_minus4ac)*1000000),
+ int_sqrt(1000000));
+ dev_dbg(data->hwmon_dev, "A_e_minus12=%lld, B_e_minus6=%d, "
"m_e_minus6=%d, n_e_minus6=%d, p_e_minus2=%d, "
- "temp=%d\n", data->A_e_minus6, data->B_e_minus2,
+ "temp=%d\n", data->A_e_minus12, data->B_e_minus6,
data->m_e_minus6,
data->n_e_minus6, data->p_e_minus2, (int)temp);
- expr1_e_minus6 = (DIV_ROUND_CLOSEST((2 * data->m_e_minus6 *
- data->B_e_minus2), 100) + data->n_e_minus6);
- dev_vdbg(data->hwmon_dev, "2_m_B_plun_e_minus6=%d\n",
- expr1_e_minus6);
- expr2_e_minus6 = (DIV_ROUND_CLOSEST(expr1_e_minus6, 1000)) *
- (DIV_ROUND_CLOSEST(expr1_e_minus6, 1000));
- dev_vdbg(data->hwmon_dev, "expr1^2=%d\n", expr2_e_minus6);
- expr3_e_minus4_1 = (DIV_ROUND_CLOSEST((
- (DIV_ROUND_CLOSEST((data->m_e_minus6 * data->B_e_minus2),
- 1000)) * (DIV_ROUND_CLOSEST(data->B_e_minus2, 10))), 100));
- dev_vdbg(data->hwmon_dev, "expr3_e_minus4_1=%d\n",
- expr3_e_minus4_1);
- expr3_e_minus4_2 = DIV_ROUND_CLOSEST(
- (DIV_ROUND_CLOSEST(data->n_e_minus6, 100) * data->B_e_minus2),
- 100);
- dev_vdbg(data->hwmon_dev, "expr3_e_minus4_2=%d\n",
- expr3_e_minus4_2);
- expr3_e_minus4 = expr3_e_minus4_1 + expr3_e_minus4_2;
- dev_vdbg(data->hwmon_dev, "expr3=%d\n", expr3_e_minus4);
- expr4_e_minus2_1 = DIV_ROUND_CLOSEST((expr3_e_minus4 +
- (data->p_e_minus2 * 100)), 100);
- dev_vdbg(data->hwmon_dev, "expr4_e_minus2_1=%d\n",
- expr4_e_minus2_1);
- expr4_e_minus6_2 = (4 * data->m_e_minus6);
- dev_vdbg(data->hwmon_dev, "expr4_e_minus6_2=%d\n",
- expr4_e_minus6_2);
- expr4_e_minus6 = DIV_ROUND_CLOSEST((expr4_e_minus2_1 *
- expr4_e_minus6_2), 100);
- dev_vdbg(data->hwmon_dev, "expr4_minus6=%d\n", expr4_e_minus6);
- expr5_e_minus6_1 = expr2_e_minus6 - expr4_e_minus6;
- dev_vdbg(data->hwmon_dev, "expr5_e_minus6_1=%d\n",
- expr5_e_minus6_1);
- expr4_e_minus6_3 = (expr4_e_minus6_2 * temp);
- dev_vdbg(data->hwmon_dev, "expr4_e_minus6_3=%d\n",
- expr4_e_minus6_3);
- expr5_e_minus6 = (expr5_e_minus6_1 + expr4_e_minus6_3);
- dev_vdbg(data->hwmon_dev, "expr5_e_minus6=%d\n",
- expr5_e_minus6);
- multiplier = my_ceil_pow10(expr5_e_minus6);
- dev_vdbg(data->hwmon_dev, "multiplier=%d\n", multiplier);
- expr6 = int_sqrt(expr5_e_minus6);
- dev_vdbg(data->hwmon_dev, "sqrt top=%d\n", expr6);
- expr7 = int_sqrt(multiplier);
- dev_vdbg(data->hwmon_dev, "sqrt bot=%d\n", expr7);
- if (expr7 == 0) {
- pr_err("Error: %s line=%d, expr7=%d\n",
- __func__, __LINE__, expr7);
- return;
- } else {
- expr8_e_minus6 = (expr6 * multiplier2) / expr7;
- }
- dev_vdbg(data->hwmon_dev, "sqrt final=%d\n", expr8_e_minus6);
- dev_vdbg(data->hwmon_dev, "2_m_B_plus_n_e_minus6=%d\n",
- expr1_e_minus6);
- expr9_e_minus6 = DIV_ROUND_CLOSEST((2 * data->m_e_minus6 *
- data->A_e_minus6), 1000000);
- dev_vdbg(data->hwmon_dev, "denominator=%d\n", expr9_e_minus6);
- if (expr9_e_minus6 == 0) {
- pr_err("Error: %s line=%d, expr9_e_minus6=%d\n",
- __func__, __LINE__, expr9_e_minus6);
- return;
- }
- expr10_e_minus6 = -expr1_e_minus6 - expr8_e_minus6;
- dev_vdbg(data->hwmon_dev, "expr10_e_minus6=%d\n",
- expr10_e_minus6);
- expr11_e_minus6 = -expr1_e_minus6 + expr8_e_minus6;
- dev_vdbg(data->hwmon_dev, "expr11_e_minus6=%d\n",
- expr11_e_minus6);
- expr12 = (expr10_e_minus6 / expr9_e_minus6);
- dev_vdbg(data->hwmon_dev, "counter1=%d\n", expr12);
- expr13 = (expr11_e_minus6 / expr9_e_minus6);
- dev_vdbg(data->hwmon_dev, "counter2=%d\n", expr13);
- *p_counter1 = expr12;
- *p_counter2 = expr13;
+ dev_dbg(data->hwmon_dev, "2mB_n=%d, 2mA=%lld, mB2_nB_p_minusTemp=%d,"
+ "b2_minus4ac=%d\n", v_e_minus6_2mB_n,
+ v_e_minus12_2mA, v_e_minus4_mB2_nB_p_minusTemp,
+ v_e_minus6_b2_minus4ac);
+
+ temp_64=(s64)(-v_e_minus6_2mB_n - v_e_minus6_sqrt_b2_minus4ac) * 1000000;
+ root1=(s32)div64_s64(temp_64, v_e_minus12_2mA);
+
+ temp_64=(s64)(-v_e_minus6_2mB_n + v_e_minus6_sqrt_b2_minus4ac) * 1000000;
+ root2=(s32)div64_s64(temp_64, v_e_minus12_2mA);
+
+ dev_dbg(data->hwmon_dev, "new expr: temp=%d, root1=%d, root2=%d\n",
+ temp, root1, root2);
+
+ *p_counter1 = root1;
+ *p_counter2 = root2;
+ /* we find that root2 is more appropriate root */
+
+ /* logs temperature -> counter conversion */
+ dev_dbg(data->hwmon_dev, "temperature=%d, counter1=%#x, "
+ "counter2=%#x\n", temp, *p_counter1, *p_counter2);
}
/*
@@ -1083,29 +1176,24 @@ static void tsensor_temp_2_count(struct tegra_tsensor_data *data,
unsigned int *p_counter1,
unsigned int *p_counter2)
{
- if (temp > 0) {
- dev_dbg(data->hwmon_dev, "Trying to calculate counter"
- " for requested temperature"
- " threshold=%d\n", temp);
- /*
- * calculate the constants needed to get roots of
- * following quadratic eqn:
- * m * A^2 * Counter^2 +
- * A * (2 * m * B + n) * Counter +
- * (m * B^2 + n * B + p - Temperature) = 0
- */
- get_quadratic_roots(data, temp, p_counter1, p_counter2);
- /*
- * checked at current temperature=35 the counter=11418
- * for 50 deg temperature: counter1=22731, counter2=11817
- * at 35 deg temperature: counter1=23137, counter2=11411
- * hence, for above values we are assuming counter2 has
- * the correct value
- */
- } else {
- *p_counter1 = DEFAULT_THRESHOLD_TH3;
- *p_counter2 = DEFAULT_THRESHOLD_TH3;
- }
+ dev_dbg(data->hwmon_dev, "Trying to calculate counter"
+ " for requested temperature"
+ " threshold=%d\n", temp);
+ /*
+ * calculate the constants needed to get roots of
+ * following quadratic eqn:
+ * m * A^2 * Counter^2 +
+ * A * (2 * m * B + n) * Counter +
+ * (m * B^2 + n * B + p - Temperature) = 0
+ */
+ get_quadratic_roots(data, temp, p_counter1, p_counter2);
+ /*
+ * checked at current temperature=35 the counter=11418
+ * for 50 deg temperature: counter1=22731, counter2=11817
+ * at 35 deg temperature: counter1=23137, counter2=11411
+ * hence, for above values we are assuming counter2 has
+ * the correct value
+ */
}
/*
@@ -1129,46 +1217,80 @@ static bool cmp_counter(
return true;
}
+/* function to print chart of counter to temperature values -
+ * It uses F1, F2, T1, T2 and start data gives reading
+ * for temperature in between the range
+ */
+static void print_counter_2_temperature_table(
+ struct tegra_tsensor_data *data)
+{
+ int i;
+ unsigned int start_counter, end_counter;
+ unsigned int diff;
+ int temperature;
+ const unsigned int num_readings = 40;
+ unsigned int index = 0;
+ dev_dbg(data->hwmon_dev, "***Counter and Temperature chart **********\n");
+ start_counter = data->fuse_F1;
+ end_counter = data->fuse_F2;
+ diff = (end_counter - start_counter) / num_readings;
+
+ /* We want to take num_readings counter values in between
+ and try to report corresponding temperature */
+ for (i = start_counter; i <= (end_counter + diff);
+ i += diff) {
+ tsensor_count_2_temp(data, i, &temperature);
+ dev_dbg(data->hwmon_dev, "[%d]: Counter=%#x, temperature=%d.%06dC\n",
+ ++index, i, get_temperature_int(temperature),
+ get_temperature_fraction(temperature));
+ }
+ dev_dbg(data->hwmon_dev, "\n\n");
+ tsensor_count_2_temp(data, end_counter, &temperature);
+ dev_dbg(data->hwmon_dev, "[%d]: Counter=%#x, temperature=%d.%06dC\n",
+ ++index, end_counter, get_temperature_int(temperature),
+ get_temperature_fraction(temperature));
+}
+
+static bool temp_matched(int given_temp, int calc_temp)
+{
+ const int temp_diff_max = 4;
+ int diff;
+
+ diff = given_temp - calc_temp;
+ if (diff < 0)
+ diff *= -1;
+ if (diff > temp_diff_max)
+ return false;
+ else
+ return true;
+}
+
/* function to print chart of temperature to counter values */
static void print_temperature_2_counter_table(
struct tegra_tsensor_data *data)
{
int i;
- /* static list of temperature tested */
- int temp_list[] = {
- 30,
- 35,
- 40,
- 45,
- 50,
- 55,
- 60,
- 61,
- 62,
- 63,
- 64,
- 65,
- 70,
- 75,
- 80,
- 85,
- 90,
- 95,
- 100,
- 105,
- 110,
- 115,
- 120
- };
+ int min = -25;
+ int max = 120;
unsigned int counter1, counter2;
+ int temperature;
+
dev_dbg(data->hwmon_dev, "Temperature and counter1 and "
"counter2 chart **********\n");
- for (i = 0; i < ARRAY_SIZE(temp_list); i++) {
- tsensor_temp_2_count(data, temp_list[i],
+ for (i = min; i <= max; i++) {
+ tsensor_temp_2_count(data, i,
&counter1, &counter2);
- dev_dbg(data->hwmon_dev, "temperature[%d]=%d, "
+ dev_dbg(data->hwmon_dev, "temperature=%d, "
"counter1=0x%x, counter2=0x%x\n",
- i, temp_list[i], counter1, counter2);
+ i, counter1, counter2);
+ /* verify the counter2 to temperature conversion */
+ tsensor_count_2_temp(data, counter2, &temperature);
+ dev_dbg(data->hwmon_dev, "Given temp=%d: counter2=%d, conv temp=%d.%06d\n",
+ i, counter2, get_temperature_int(temperature),
+ get_temperature_fraction(temperature));
+ if (!temp_matched(i, get_temperature_round(temperature)))
+ dev_dbg(data->hwmon_dev, "tsensor temp to counter to temp conversion failed for temp=%d\n",
+ i);
}
dev_dbg(data->hwmon_dev, "\n\n");
}
@@ -1226,7 +1348,7 @@ static int test_temperature_algo(struct tegra_tsensor_data *data)
/* calculate temperature */
err = tsensor_count_2_temp(data, actual_counter, &T1);
dev_dbg(data->hwmon_dev, "%s actual counter=0x%x, calculated "
- "temperature=%d.%d\n", __func__,
+ "temperature=%d.%06d\n", __func__,
actual_counter, get_temperature_int(T1),
get_temperature_fraction(T1));
if (err < 0) {
@@ -1552,6 +1674,9 @@ static void tsensor_work_func(struct work_struct *work)
data->alert_func(data->alert_data);
if (!tsensor_within_limits(data))
+ dev_dbg(data->hwmon_dev,
+ "repeated work queueing state=%d\n",
+ get_ts_state(data));
queue_delayed_work(data->workqueue, &data->work,
HZ * DEFAULT_TSENSOR_M /
DEFAULT_TSENSOR_CLK_HZ);
@@ -1656,6 +1781,8 @@ static int tegra_tsensor_setup(struct platform_device *pdev)
print_temperature_2_counter_table(data);
+ print_counter_2_temperature_table(data);
+
/* EDP and throttling support using tsensor enabled
* based on fuse revision */
err = tegra_fuse_get_revision(&reg);
@@ -1885,6 +2012,8 @@ static int tsensor_suspend(struct platform_device *pdev,
struct tegra_tsensor_data *data = platform_get_drvdata(pdev);
unsigned int config0;
+ disable_irq(data->irq);
+ cancel_delayed_work_sync(&data->work);
/* set STOP bit, else OVERFLOW interrupt seen in LP1 */
config0 = tsensor_readl(data, ((data->instance << 16) | SENSOR_CFG0));
config0 |= (1 << SENSOR_CFG0_STOP_SHIFT);
@@ -1915,6 +2044,7 @@ static int tsensor_resume(struct platform_device *pdev)
if (data->is_edp_supported)
schedule_delayed_work(&data->work, 0);
+ enable_irq(data->irq);
return 0;
}
#endif
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 25ad6dca3884..1358dc70b0e4 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -331,12 +331,19 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev)
{
u32 val;
int tx_fifo_avail;
- u8 *buf = i2c_dev->msg_buf;
- size_t buf_remaining = i2c_dev->msg_buf_remaining;
+ u8 *buf;
+ size_t buf_remaining;
int words_to_transfer;
unsigned long flags;
spin_lock_irqsave(&i2c_dev->fifo_lock, flags);
+ if (!i2c_dev->msg_buf_remaining) {
+ spin_unlock_irqrestore(&i2c_dev->fifo_lock, flags);
+ return 0;
+ }
+
+ buf = i2c_dev->msg_buf;
+ buf_remaining = i2c_dev->msg_buf_remaining;
val = i2c_readl(i2c_dev, I2C_FIFO_STATUS);
tx_fifo_avail = (val & I2C_FIFO_STATUS_TX_MASK) >>
@@ -375,7 +382,12 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev)
* boundary and fault.
*/
if (tx_fifo_avail > 0 && buf_remaining > 0) {
- BUG_ON(buf_remaining > 3);
+ if (buf_remaining > 3) {
+ dev_err(i2c_dev->dev,
+ "Remaining buffer more than 3 %d\n",
+ buf_remaining);
+ BUG();
+ }
memcpy(&val, buf, buf_remaining);
/* Again update before writing to FIFO to make sure isr sees. */
@@ -583,9 +595,12 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
}
i2c_writel(i2c_dev, status, I2C_INT_STATUS);
+ i2c_readl(i2c_dev, I2C_INT_STATUS);
- if (i2c_dev->is_dvc)
+ if (i2c_dev->is_dvc) {
dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS);
+ dvc_readl(i2c_dev, DVC_STATUS);
+ }
if (status & I2C_INT_PACKET_XFER_COMPLETE) {
BUG_ON(i2c_dev->msg_buf_remaining);
@@ -621,13 +636,16 @@ err:
I2C_INT_RX_FIFO_DATA_REQ | I2C_INT_TX_FIFO_OVERFLOW);
i2c_writel(i2c_dev, status, I2C_INT_STATUS);
+ i2c_readl(i2c_dev, I2C_INT_STATUS);
/* An error occured, mask dvc interrupt */
if (i2c_dev->is_dvc)
dvc_i2c_mask_irq(i2c_dev, DVC_CTRL_REG3_I2C_DONE_INTR_EN);
- if (i2c_dev->is_dvc)
+ if (i2c_dev->is_dvc) {
dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS);
+ dvc_readl(i2c_dev, DVC_STATUS);
+ }
complete(&i2c_dev->msg_complete);
return IRQ_HANDLED;
diff --git a/drivers/input/misc/cm3217.c b/drivers/input/misc/cm3217.c
index 9c9b60d69619..416d0b3806a9 100644
--- a/drivers/input/misc/cm3217.c
+++ b/drivers/input/misc/cm3217.c
@@ -3,6 +3,8 @@
* Copyright (C) 2011 Capella Microsystems Inc.
* Author: Frank Hsieh <pengyueh@gmail.com>
*
+ * Copyright (c) 2012, NVIDIA Corporation.
+ *
* 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.
@@ -36,11 +38,11 @@
#include <asm/mach-types.h>
#include <asm/setup.h>
-#define D(x...) pr_info(x)
+#define D(x...) pr_debug(x)
#define I2C_RETRY_COUNT 10
-#define LS_POLLING_DELAY 500
+#define LS_POLLING_DELAY 1000 /* mSec */
static void report_do_work(struct work_struct *w);
static DECLARE_DELAYED_WORK(report_work, report_do_work);
@@ -382,20 +384,8 @@ static int lightsensor_enable(struct cm3217_info *lpi)
if (ret < 0)
pr_err("[LS][CM3217 error]%s: set auto light sensor fail\n",
__func__);
- else {
- msleep(50); /* wait for 50 ms for the first report adc */
-
- /* report an invalid value first to ensure we
- * trigger an event when adc_level is zero.
- */
- input_report_abs(lpi->ls_input_dev, ABS_MISC, -1);
- input_sync(lpi->ls_input_dev);
- /* resume, IOCTL and DEVICE_ATTR */
- report_lsensor_input_event(lpi, 1);
- lpi->als_enable = 1;
- }
- queue_delayed_work(lpi->lp_wq, &report_work, lpi->polling_delay);
+ queue_work(lpi->lp_wq, &report_work);
lpi->als_enable = 1;
mutex_unlock(&als_enable_mutex);
@@ -458,8 +448,10 @@ static int lightsensor_release(struct inode *inode, struct file *file)
static long lightsensor_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
- int rc, val;
+ int rc = 0;
+ int val;
struct cm3217_info *lpi = lp_info;
+ unsigned long delay;
/* D("[CM3217] %s cmd %d\n", __func__, _IOC_NR(cmd)); */
@@ -481,6 +473,17 @@ static long lightsensor_ioctl(struct file *file, unsigned int cmd,
rc = put_user(val, (unsigned long __user *)arg);
break;
+ case LIGHTSENSOR_IOCTL_SET_DELAY:
+ if (get_user(delay, (unsigned long __user *)arg)) {
+ rc = -EFAULT;
+ break;
+ }
+ D("[LS][CM3217] %s LIGHTSENSOR_IOCTL_SET_DELAY, delay %ld\n",
+ __func__, delay);
+ delay = delay / 1000;
+ lpi->polling_delay = msecs_to_jiffies(delay);
+ break;
+
default:
pr_err("[LS][CM3217 error]%s: invalid cmd %d\n",
__func__, _IOC_NR(cmd));
diff --git a/drivers/input/touchscreen/rmi4/rmi_driver.c b/drivers/input/touchscreen/rmi4/rmi_driver.c
index 6aeb3b93b2c5..78b30095b086 100644
--- a/drivers/input/touchscreen/rmi4/rmi_driver.c
+++ b/drivers/input/touchscreen/rmi4/rmi_driver.c
@@ -106,9 +106,9 @@ static ssize_t rmi_delay_store(struct device *dev,
static struct device_attribute attrs[] = {
__ATTR(hasbsr, RMI_RO_ATTR,
rmi_driver_hasbsr_show, rmi_store_error),
- __ATTR(bsr, RMI_RW_ATTR,
+ __ATTR(bsr, RMI_RO_ATTR,
rmi_driver_bsr_show, rmi_driver_bsr_store),
- __ATTR(enabled, RMI_RW_ATTR,
+ __ATTR(enabled, RMI_RO_ATTR,
rmi_driver_enabled_show, rmi_driver_enabled_store),
__ATTR(phys, RMI_RO_ATTR,
rmi_driver_phys_show, rmi_store_error),
diff --git a/drivers/input/touchscreen/rmi4/rmi_f01.c b/drivers/input/touchscreen/rmi4/rmi_f01.c
index ef9adb0586b9..6ccdf2443609 100644
--- a/drivers/input/touchscreen/rmi4/rmi_f01.c
+++ b/drivers/input/touchscreen/rmi4/rmi_f01.c
@@ -187,13 +187,13 @@ static struct device_attribute fn_01_attrs[] = {
rmi_fn_01_datecode_show, rmi_store_error),
/* control register access */
- __ATTR(sleepmode, RMI_RW_ATTR,
+ __ATTR(sleepmode, RMI_RO_ATTR,
rmi_fn_01_sleepmode_show, rmi_fn_01_sleepmode_store),
- __ATTR(nosleep, RMI_RW_ATTR,
+ __ATTR(nosleep, RMI_RO_ATTR,
rmi_fn_01_nosleep_show, rmi_fn_01_nosleep_store),
- __ATTR(chargerinput, RMI_RW_ATTR,
+ __ATTR(chargerinput, RMI_RO_ATTR,
rmi_fn_01_chargerinput_show, rmi_fn_01_chargerinput_store),
- __ATTR(reportrate, RMI_RW_ATTR,
+ __ATTR(reportrate, RMI_RO_ATTR,
rmi_fn_01_reportrate_show, rmi_fn_01_reportrate_store),
/* We make report rate RO, since the driver uses that to look for
* resets. We don't want someone faking us out by changing that
@@ -203,7 +203,7 @@ static struct device_attribute fn_01_attrs[] = {
rmi_fn_01_configured_show, rmi_store_error),
/* Command register access. */
- __ATTR(reset, RMI_WO_ATTR,
+ __ATTR(reset, RMI_RO_ATTR,
rmi_show_error, rmi_fn_01_reset_store),
/* STatus register access. */
diff --git a/drivers/input/touchscreen/rmi4/rmi_f09.c b/drivers/input/touchscreen/rmi4/rmi_f09.c
index 0ec980d7db07..4328d49ddcbf 100644
--- a/drivers/input/touchscreen/rmi4/rmi_f09.c
+++ b/drivers/input/touchscreen/rmi4/rmi_f09.c
@@ -86,13 +86,13 @@ static ssize_t rmi_f09_HostTestEn_show(struct device *dev,
static ssize_t rmi_f09_HostTestEn_store(struct device *dev,
struct device_attribute *attr,
- char *buf, size_t count);
-
-static ssize_t rmi_f09_InternalLimits_show(struct device *dev,
- struct device_attribute *attr, char *buf);
+ const char *buf, size_t count);
static ssize_t rmi_f09_Result_Register_Count_show(struct device *dev,
struct device_attribute *attr, char *buf);
+#if defined(RMI_SYS_ATTR)
+static ssize_t rmi_f09_InternalLimits_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
static ssize_t rmi_f09_Overall_BIST_Result_show(struct device *dev,
struct device_attribute *attr, char *buf);
@@ -100,6 +100,7 @@ static ssize_t rmi_f09_Overall_BIST_Result_show(struct device *dev,
static ssize_t rmi_f09_Overall_BIST_Result_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count);
+#endif
static struct device_attribute attrs[] = {
__ATTR(Limit_Register_Count, RMI_RO_ATTR,
@@ -119,7 +120,6 @@ static int rmi_f09_init(struct rmi_function_container *fc)
struct rmi_fn_09_data *f09;
u8 query_base_addr;
int rc;
- int i;
int attr_count = 0;
int retval = 0;
@@ -171,8 +171,8 @@ static void rmi_f09_remove(struct rmi_function_container *fc)
{
struct rmi_fn_09_data *data = fc->data;
if (data) {
- kfree(data->query.Limit_Register_Count);
- kfree(data->query.f09_bist_query1);
+ kfree(&data->query.Limit_Register_Count);
+ kfree(&data->query.f09_bist_query1);
}
kfree(fc->data);
}
@@ -230,7 +230,7 @@ static ssize_t rmi_f09_HostTestEn_show(struct device *dev,
static ssize_t rmi_f09_HostTestEn_store(struct device *dev,
struct device_attribute *attr,
- char *buf, size_t count)
+ const char *buf, size_t count)
{
struct rmi_function_container *fc;
struct rmi_fn_09_data *data;
@@ -264,7 +264,8 @@ static ssize_t rmi_f09_HostTestEn_store(struct device *dev,
}
-static ssize_t rmi_f09_InternalLimits_show(struct device *dev,
+#if defined(RMI_SYS_ATTR)
+ ssize_t rmi_f09_InternalLimits_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
@@ -276,6 +277,7 @@ static ssize_t rmi_f09_InternalLimits_show(struct device *dev,
return snprintf(buf, PAGE_SIZE, "%u\n",
data->query.InternalLimits);
}
+#endif
static ssize_t rmi_f09_Result_Register_Count_show(struct device *dev,
struct device_attribute *attr,
diff --git a/drivers/input/touchscreen/rmi4/rmi_f11.c b/drivers/input/touchscreen/rmi4/rmi_f11.c
index 35bb945143de..7530720d61f1 100644
--- a/drivers/input/touchscreen/rmi4/rmi_f11.c
+++ b/drivers/input/touchscreen/rmi4/rmi_f11.c
@@ -99,15 +99,15 @@ static ssize_t rmi_f11_rezero_store(struct device *dev,
static struct device_attribute attrs[] = {
- __ATTR(flip, RMI_RW_ATTR, rmi_fn_11_flip_show, rmi_fn_11_flip_store),
- __ATTR(clip, RMI_RW_ATTR, rmi_fn_11_clip_show, rmi_fn_11_clip_store),
- __ATTR(offset, RMI_RW_ATTR,
+ __ATTR(flip, RMI_RO_ATTR, rmi_fn_11_flip_show, rmi_fn_11_flip_store),
+ __ATTR(clip, RMI_RO_ATTR, rmi_fn_11_clip_show, rmi_fn_11_clip_store),
+ __ATTR(offset, RMI_RO_ATTR,
rmi_fn_11_offset_show, rmi_fn_11_offset_store),
- __ATTR(swap, RMI_RW_ATTR, rmi_fn_11_swap_show, rmi_fn_11_swap_store),
- __ATTR(relreport, RMI_RW_ATTR,
+ __ATTR(swap, RMI_RO_ATTR, rmi_fn_11_swap_show, rmi_fn_11_swap_store),
+ __ATTR(relreport, RMI_RO_ATTR,
rmi_fn_11_relreport_show, rmi_fn_11_relreport_store),
__ATTR(maxPos, RMI_RO_ATTR, rmi_fn_11_maxPos_show, rmi_store_error),
- __ATTR(rezero, RMI_WO_ATTR, rmi_show_error, rmi_f11_rezero_store)
+ __ATTR(rezero, RMI_RO_ATTR, rmi_show_error, rmi_f11_rezero_store)
};
diff --git a/drivers/input/touchscreen/rmi4/rmi_f34.c b/drivers/input/touchscreen/rmi4/rmi_f34.c
index 33e84d2cfb24..abade244b834 100644
--- a/drivers/input/touchscreen/rmi4/rmi_f34.c
+++ b/drivers/input/touchscreen/rmi4/rmi_f34.c
@@ -124,9 +124,9 @@ static struct device_attribute attrs[] = {
rmi_fn_34_status_show, rmi_store_error),
/* Also, sysfs will need to have a file set up to distinguish
* between commands - like Config write/read, Image write/verify. */
- __ATTR(cmd, RMI_RW_ATTR,
+ __ATTR(cmd, RMI_RO_ATTR,
rmi_fn_34_cmd_show, rmi_fn_34_cmd_store),
- __ATTR(bootloaderid, RMI_RW_ATTR,
+ __ATTR(bootloaderid, RMI_RO_ATTR,
rmi_fn_34_bootloaderid_show, rmi_fn_34_bootloaderid_store),
__ATTR(blocksize, RMI_RO_ATTR,
rmi_fn_34_blocksize_show, rmi_store_error),
@@ -134,16 +134,16 @@ static struct device_attribute attrs[] = {
rmi_fn_34_imageblockcount_show, rmi_store_error),
__ATTR(configblockcount, RMI_RO_ATTR,
rmi_fn_34_configblockcount_show, rmi_store_error),
- __ATTR(blocknum, RMI_RW_ATTR,
+ __ATTR(blocknum, RMI_RO_ATTR,
rmi_fn_34_blocknum_show, rmi_fn_34_blocknum_store),
- __ATTR(rescanPDT, RMI_WO_ATTR,
+ __ATTR(rescanPDT, RMI_RO_ATTR,
rmi_show_error, rmi_fn_34_rescanPDT_store)
};
struct bin_attribute dev_attr_data = {
.attr = {
.name = "data",
- .mode = 0666},
+ .mode = 0644},
.size = 0,
.read = rmi_fn_34_data_read,
.write = rmi_fn_34_data_write,
diff --git a/drivers/input/touchscreen/rmi4/rmi_f54.c b/drivers/input/touchscreen/rmi4/rmi_f54.c
index 11bb0b934bef..f4f2e3ac2903 100644
--- a/drivers/input/touchscreen/rmi4/rmi_f54.c
+++ b/drivers/input/touchscreen/rmi4/rmi_f54.c
@@ -303,11 +303,11 @@ static ssize_t rmi_fn_54_fifoindex_store(struct device *dev,
const char *buf, size_t count);
static struct device_attribute attrs[] = {
- __ATTR(report_type, RMI_RW_ATTR,
+ __ATTR(report_type, RMI_RO_ATTR,
rmi_fn_54_report_type_show, rmi_fn_54_report_type_store),
- __ATTR(get_report, RMI_WO_ATTR,
+ __ATTR(get_report, RMI_RO_ATTR,
rmi_show_error, rmi_fn_54_get_report_store),
- __ATTR(force_cal, RMI_WO_ATTR,
+ __ATTR(force_cal, RMI_RO_ATTR,
rmi_show_error, rmi_fn_54_force_cal_store),
__ATTR(status, RMI_RO_ATTR,
rmi_fn_54_status_show, rmi_store_error),
@@ -358,9 +358,9 @@ static struct device_attribute attrs[] = {
rmi_fn_54_has_perf_frequency_noisecontrol_show, rmi_store_error),
__ATTR(number_of_sensing_frequencies, RMI_RO_ATTR,
rmi_fn_54_number_of_sensing_frequencies_show, rmi_store_error),
- __ATTR(no_auto_cal, RMI_RW_ATTR,
+ __ATTR(no_auto_cal, RMI_RO_ATTR,
rmi_fn_54_no_auto_cal_show, rmi_fn_54_no_auto_cal_store),
- __ATTR(fifoindex, RMI_RW_ATTR,
+ __ATTR(fifoindex, RMI_RO_ATTR,
rmi_fn_54_fifoindex_show, rmi_fn_54_fifoindex_store),
};
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index bf33c0302257..7b5ef3ffb7d0 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -38,6 +38,9 @@
#include <mach/smmu.h>
#include <mach/tegra_smmu.h>
+/* REVISIT: With new configurations for t114/124/148 passed from DT */
+#define SKIP_SWGRP_CHECK
+
/* bitmap of the page sizes currently supported */
#define SMMU_IOMMU_PGSIZES (SZ_4K)
@@ -316,11 +319,15 @@ static int __smmu_client_set_hwgrp(struct smmu_client *c,
offs = HWGRP_ASID_REG(i);
val = smmu_read(smmu, offs);
if (on) {
+#if !defined(SKIP_SWGRP_CHECK)
if (WARN_ON(val & mask))
goto err_hw_busy;
+#endif
val |= mask;
} else {
+#if !defined(SKIP_SWGRP_CHECK)
WARN_ON((val & mask) == mask);
+#endif
val &= ~mask;
}
smmu_write(smmu, val, offs);
@@ -701,9 +708,15 @@ static int smmu_iommu_attach_dev(struct iommu_domain *domain,
return -ENOMEM;
client->dev = dev;
client->as = as;
+
+#ifdef SKIP_SWGRP_CHECK
+ /* Enable all SWGRP blindly by default */
+ map = (1 << HWGRP_COUNT) - 1;
+#else
map = (unsigned long)dev->platform_data;
if (!map)
return -EINVAL;
+#endif
err = smmu_client_enable_hwgrp(client, map);
if (err)
@@ -1028,5 +1041,5 @@ static void __exit tegra_smmu_exit(void)
platform_driver_unregister(&tegra_smmu_driver);
}
-subsys_initcall(tegra_smmu_init);
+core_initcall(tegra_smmu_init);
module_exit(tegra_smmu_exit);
diff --git a/drivers/media/video/tegra/Kconfig b/drivers/media/video/tegra/Kconfig
index 404d771a717e..5099fe12c3e2 100644
--- a/drivers/media/video/tegra/Kconfig
+++ b/drivers/media/video/tegra/Kconfig
@@ -27,6 +27,13 @@ config VIDEO_OV5650
This is a driver for the Omnivision OV5650 5MP camera sensor
for use with the tegra isp.
+config VIDEO_OV5640
+ tristate "OV5640 camera sensor support"
+ depends on I2C && ARCH_TEGRA
+ ---help---
+ This is a driver for the Omnivision OV5640 5MP camera sensor
+ for use with the tegra isp.
+
config VIDEO_OV14810
tristate "OV14810 camera sensor support"
depends on I2C && ARCH_TEGRA
@@ -88,3 +95,10 @@ config VIDEO_AD5820
---help---
This is a driver for the AD5820 focuser
for use with the tegra isp.
+
+config VIDEO_AD5816
+ tristate "AD5816 focuser support"
+ depends on I2C && ARCH_TEGRA
+ ---help---
+ This is a driver for the AD5816 focuser
+ for use with the tegra isp.
diff --git a/drivers/media/video/tegra/Makefile b/drivers/media/video/tegra/Makefile
index 5d404e44fd20..7d7285e06fb7 100644
--- a/drivers/media/video/tegra/Makefile
+++ b/drivers/media/video/tegra/Makefile
@@ -1,4 +1,6 @@
GCOV_PROFILE := y
+
+subdir-ccflags-y := -Werror
#
# Makefile for the video capture/playback device drivers.
#
@@ -9,6 +11,7 @@ obj-$(CONFIG_TEGRA_DTV) += tegra_dtv.o
obj-$(CONFIG_TEGRA_CAMERA) += tegra_camera.o
obj-$(CONFIG_VIDEO_AR0832) += ar0832_main.o
obj-$(CONFIG_VIDEO_OV5650) += ov5650.o
+obj-$(CONFIG_VIDEO_OV5640) += ov5640.o
obj-$(CONFIG_VIDEO_OV14810) += ov14810.o
obj-$(CONFIG_VIDEO_OV9726) += ov9726.o
obj-$(CONFIG_VIDEO_OV2710) += ov2710.o
@@ -17,4 +20,5 @@ obj-$(CONFIG_TORCH_SSL3250A) += ssl3250a.o
obj-$(CONFIG_TORCH_TPS61050) += tps61050.o
obj-$(CONFIG_VIDEO_SH532U) += sh532u.o
obj-$(CONFIG_VIDEO_AD5820) += ad5820.o
+obj-$(CONFIG_VIDEO_AD5816) += ad5816.o
diff --git a/drivers/media/video/tegra/ad5816.c b/drivers/media/video/tegra/ad5816.c
new file mode 100644
index 000000000000..9e31acc33cc3
--- /dev/null
+++ b/drivers/media/video/tegra/ad5816.c
@@ -0,0 +1,1188 @@
+/* Copyright (C) 2011-2012 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU 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
+ */
+/* This is a NVC kernel driver for a focuser device called
+ * ad5816.
+ */
+/* Implementation
+ * --------------
+ * The board level details about the device need to be provided in the board
+ * file with the <device>_platform_data structure.
+ * Standard among NVC kernel drivers in this structure is:
+ * .cfg = Use the NVC_CFG_ defines that are in nvc.h.
+ * Descriptions of the configuration options are with the defines.
+ * This value is typically 0.
+ * .num = The number of the instance of the device. This should start at 1 and
+ * and increment for each device on the board. This number will be
+ * appended to the MISC driver name, Example: /dev/focuser.1
+ * If not used or 0, then nothing is appended to the name.
+ * .sync = If there is a need to synchronize two devices, then this value is
+ * the number of the device instance (.num above) this device is to
+ * sync to. For example:
+ * Device 1 platform entries =
+ * .num = 1,
+ * .sync = 2,
+ * Device 2 platfrom entries =
+ * .num = 2,
+ * .sync = 1,
+ * The above example sync's device 1 and 2.
+ * To disable sync, set .sync = 0. Note that the .num = 0 device is not
+ * allowed to be synced to.
+ * This is typically used for stereo applications.
+ * .dev_name = The MISC driver name the device registers as. If not used,
+ * then the part number of the device is used for the driver name.
+ * If using the NVC user driver then use the name found in this
+ * driver under _default_pdata.
+ * .gpio_count = The ARRAY_SIZE of the nvc_gpio_pdata table.
+ * .gpio = A pointer to the nvc_gpio_pdata structure's platform GPIO data.
+ * The GPIO mechanism works by cross referencing the .gpio_type key
+ * among the nvc_gpio_pdata GPIO data and the driver's nvc_gpio_init
+ * GPIO data to build a GPIO table the driver can use. The GPIO's
+ * defined in the device header file's _gpio_type enum are the
+ * gpio_type keys for the nvc_gpio_pdata and nvc_gpio_init structures.
+ * These need to be present in the board file's nvc_gpio_pdata
+ * structure for the GPIO's that are used.
+ * The driver's GPIO logic uses assert/deassert throughout until the
+ * low level _gpio_wr/rd calls where the .assert_high is used to
+ * convert the value to the correct signal level.
+ * See the GPIO notes in nvc.h for additional information.
+ *
+ * The following is specific to NVC kernel focus drivers:
+ * .nvc = Pointer to the nvc_focus_nvc structure. This structure needs to
+ * be defined and populated if overriding the driver defaults.
+ * .cap = Pointer to the nvc_focus_cap structure. This structure needs to
+ * be defined and populated if overriding the driver defaults.
+ *
+ * The following is specific to this NVC kernel focus driver:
+ * .info = Pointer to the ad5816_pdata_info structure. This structure does
+ * not need to be defined and populated unless overriding ROM data.
+ *
+ * Power Requirements:
+ * The device's header file defines the voltage regulators needed with the
+ * enumeration <device>_vreg. The order these are enumerated is the order
+ * the regulators will be enabled when powering on the device. When the
+ * device is powered off the regulators are disabled in descending order.
+ * The <device>_vregs table in this driver uses the nvc_regulator_init
+ * structure to define the regulator ID strings that go with the regulators
+ * defined with <device>_vreg. These regulator ID strings (or supply names)
+ * will be used in the regulator_get function in the _vreg_init function.
+ * The board power file and <device>_vregs regulator ID strings must match.
+ */
+
+#include <linux/fs.h>
+#include <linux/i2c.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+#include <linux/list.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio.h>
+#include <media/ad5816.h>
+
+#define AD5816_ID 0x04
+#define AD5816_FOCAL_LENGTH (4.570f)
+#define AD5816_FNUMBER (2.8f)
+#define AD5816_ACTUATOR_RANGE 680
+#define AD5816_SETTLETIME 110
+#define AD5816_FOCUS_MACRO 810
+#define AD5816_FOCUS_INFINITY 50 /* Exact value needs to be decided */
+#define AD5816_POS_LOW_DEFAULT 220
+#define AD5816_POS_HIGH_DEFAULT 900
+/* Need to decide exact value of VCM_THRESHOLD and its use */
+/* define AD5816_VCM_THRESHOLD 20 */
+
+static u8 ad5816_ids[] = {
+ 0x04,
+};
+
+static struct nvc_gpio_init ad5816_gpios[] = {
+ { AD5816_GPIO_RESET, GPIOF_OUT_INIT_LOW, "reset", false, true, },
+ { AD5816_GPIO_I2CMUX, 0, "i2c_mux", 0, false},
+ { AD5816_GPIO_GP1, 0, "gp1", 0, false},
+ { AD5816_GPIO_GP2, 0, "gp2", 0, false},
+ { AD5816_GPIO_GP3, 0, "gp3", 0, false},
+};
+
+static struct nvc_regulator_init ad5816_vregs[] = {
+ { AD5816_VREG_VDD, "vdd"},
+ { AD5816_VREG_VDD_AF, "vdd_af"},
+ { AD5816_VREG_VDD_I2C, "vdd_i2c"},
+};
+
+struct ad5816_info {
+ atomic_t in_use;
+ struct i2c_client *i2c_client;
+ struct ad5816_platform_data *pdata;
+ struct miscdevice miscdev;
+ struct list_head list;
+ struct nvc_gpio gpio[ARRAY_SIZE(ad5816_gpios)];
+ struct nvc_regulator vreg[ARRAY_SIZE(ad5816_vregs)];
+ int pwr_api;
+ int pwr_dev;
+ int id_minor;
+ u32 pos;
+ u8 s_mode;
+ bool reset_flag;
+ struct ad5816_info *s_info;
+ struct nvc_focus_nvc nvc;
+ struct nvc_focus_cap cap;
+ struct ad5816_pdata_info config;
+};
+
+/**
+ * The following are default values
+ */
+
+static struct ad5816_pdata_info ad5816_default_info = {
+ .pos_low = AD5816_POS_LOW_DEFAULT,
+ .pos_high = AD5816_POS_HIGH_DEFAULT,
+};
+
+static struct nvc_focus_cap ad5816_default_cap = {
+ .version = NVC_FOCUS_CAP_VER2,
+ .actuator_range = AD5816_ACTUATOR_RANGE,
+ .settle_time = AD5816_SETTLETIME,
+ .focus_macro = AD5816_FOCUS_MACRO,
+ .focus_infinity = AD5816_FOCUS_INFINITY,
+};
+
+static struct nvc_focus_nvc ad5816_default_nvc = {
+ .focal_length = AD5816_FOCAL_LENGTH,
+ .fnumber = AD5816_FNUMBER,
+};
+
+static struct ad5816_platform_data ad5816_default_pdata = {
+ .cfg = 0,
+ .num = 0,
+ .sync = 0,
+ .dev_name = "focuser",
+};
+static LIST_HEAD(ad5816_info_list);
+static DEFINE_SPINLOCK(ad5816_spinlock);
+
+static int ad5816_i2c_rd8(struct ad5816_info *info, u8 addr, u8 reg, u8 *val)
+{
+ struct i2c_msg msg[2];
+ u8 buf[2];
+ buf[0] = reg;
+ if (addr) {
+ msg[0].addr = addr;
+ msg[1].addr = addr;
+ } else {
+ msg[0].addr = info->i2c_client->addr;
+ msg[1].addr = info->i2c_client->addr;
+ }
+ msg[0].flags = 0;
+ msg[0].len = 1;
+ msg[0].buf = &buf[0];
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = 1;
+ msg[1].buf = &buf[1];
+ *val = 0;
+ if (i2c_transfer(info->i2c_client->adapter, msg, 2) != 2)
+ return -EIO;
+ *val = buf[1];
+ return 0;
+}
+
+static int ad5816_i2c_wr8(struct ad5816_info *info, u8 reg, u8 val)
+{
+ struct i2c_msg msg;
+ u8 buf[2];
+ buf[0] = reg;
+ buf[1] = val;
+ msg.addr = info->i2c_client->addr;
+ msg.flags = 0;
+ msg.len = 2;
+ msg.buf = &buf[0];
+ if (i2c_transfer(info->i2c_client->adapter, &msg, 1) != 1)
+ return -EIO;
+ return 0;
+}
+
+static int ad5816_i2c_rd16(struct ad5816_info *info, u8 reg, u16 *val)
+{
+ struct i2c_msg msg[2];
+ u8 buf[3];
+ buf[0] = reg;
+ msg[0].addr = info->i2c_client->addr;
+ msg[0].flags = 0;
+ msg[0].len = 1;
+ msg[0].buf = &buf[0];
+ msg[1].addr = info->i2c_client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = 2;
+ msg[1].buf = &buf[1];
+ if (i2c_transfer(info->i2c_client->adapter, msg, 2) != 2)
+ return -EIO;
+ *val = (((u16)buf[1] << 8) | (u16)buf[2]);
+ return 0;
+}
+
+static int ad5816_i2c_wr16(struct ad5816_info *info, u8 reg, u16 val)
+{
+ struct i2c_msg msg;
+ u8 buf[3];
+ buf[0] = reg;
+ buf[1] = (u8)(val >> 8);
+ buf[2] = (u8)(val & 0xff);
+ msg.addr = info->i2c_client->addr;
+ msg.flags = 0;
+ msg.len = 3;
+ msg.buf = &buf[0];
+ if (i2c_transfer(info->i2c_client->adapter, &msg, 1) != 1)
+ return -EIO;
+ return 0;
+}
+
+static int ad5816_gpio_wr(struct ad5816_info *info, ad5816_gpio_types i,
+ int val) /* val: 0=deassert, 1=assert */
+{
+ int err = -EINVAL;
+ if (info->gpio[i].valid) {
+ val = !!val;
+ if (!info->gpio[i].active_high)
+ val = !val;
+ err = val;
+ gpio_set_value_cansleep(info->gpio[i].gpio, val);
+ dev_dbg(&info->i2c_client->dev, "%s %u %d\n", __func__, info->gpio[i].gpio, val);
+ }
+ return err; /* return value written or error */
+}
+
+static int ad5816_gpio_reset(struct ad5816_info *info, int val)
+{
+ int err = 0;
+
+ if (val) {
+ if(!info->reset_flag) {
+ info->reset_flag = true;
+ err = ad5816_gpio_wr(info, AD5816_GPIO_RESET, 1);
+ if (err < 0)
+ return 0; /* flag no reset */
+
+ mdelay(1);
+ ad5816_gpio_wr(info, AD5816_GPIO_RESET, 0);
+ mdelay(10); /* startup delay needs to be modified*/
+ err = 1; /* flag that a reset was done */
+ }
+ } else {
+ info->reset_flag = false;
+ }
+ return err;
+}
+
+static void ad5816_gpio_able(struct ad5816_info *info, int val)
+{
+ /**
+ * This is a feature that allows driver to control GPIOs
+ * that may be needed for the board (not the device).
+ * */
+ if (val) {
+ ad5816_gpio_wr(info, AD5816_GPIO_GP1, val);
+ ad5816_gpio_wr(info, AD5816_GPIO_GP2, val);
+ ad5816_gpio_wr(info, AD5816_GPIO_GP3, val);
+ } else {
+ ad5816_gpio_wr(info, AD5816_GPIO_GP3, val);
+ ad5816_gpio_wr(info, AD5816_GPIO_GP2, val);
+ ad5816_gpio_wr(info, AD5816_GPIO_GP1, val);
+ }
+}
+static void ad5816_gpio_exit(struct ad5816_info *info)
+{
+ unsigned i;
+ for (i = 0; i <= ARRAY_SIZE(ad5816_gpios); i++) {
+ if (info->gpio[i].flag && info->gpio[i].own) {
+ gpio_free(info->gpio[i].gpio);
+ info->gpio[i].own = false;
+ }
+ }
+}
+
+static void ad5816_gpio_init(struct ad5816_info *info)
+{
+ char label[32];
+ unsigned long flags;
+ unsigned type;
+ unsigned i;
+ unsigned j;
+ int err;
+ for (i = 0; i < ARRAY_SIZE(ad5816_gpios); i++)
+ info->gpio[i].flag = false;
+
+ if (!info->pdata->gpio_count || !info->pdata->gpio)
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(ad5816_gpios); i++) {
+ type = ad5816_gpios[i].gpio_type;
+
+ for (j = 0; j < info->pdata->gpio_count; j++) {
+ if (type == info->pdata->gpio[j].gpio_type)
+ break;
+ }
+
+ if (j == info->pdata->gpio_count)
+ continue;
+ info->gpio[type].gpio = info->pdata->gpio[j].gpio;
+ info->gpio[type].flag = true;
+
+ if (ad5816_gpios[i].use_flags) {
+ flags = ad5816_gpios[i].flags;
+ info->gpio[type].active_high = ad5816_gpios[i].active_high;
+ } else {
+ info->gpio[type].active_high = info->pdata->gpio[j].active_high;
+ if (info->gpio[type].active_high)
+ flags = GPIOF_OUT_INIT_LOW;
+ else
+ flags = GPIOF_OUT_INIT_HIGH;
+ }
+
+ if (!info->pdata->gpio[j].init_en)
+ continue;
+ snprintf(label, sizeof(label), "ad5816_%u_%s",
+ info->pdata->num, ad5816_gpios[i].label);
+ err = gpio_request_one(info->gpio[type].gpio, flags, label);
+ if (err) {
+ dev_err(&info->i2c_client->dev, "%s ERR %s %u\n",
+ __func__, label, info->gpio[type].gpio);
+ } else {
+ info->gpio[type].own = true;
+ dev_dbg(&info->i2c_client->dev, "%s %s %u\n",
+ __func__, label, info->gpio[type].gpio);
+ }
+ }
+}
+
+static int ad5816_vreg_dis(struct ad5816_info *info, ad5816_vreg i)
+{
+ int err = 0;
+ if (info->vreg[i].vreg_flag && (info->vreg[i].vreg != NULL)) {
+ err = regulator_disable(info->vreg[i].vreg);
+ if (!err)
+ dev_dbg(&info->i2c_client->dev, "%s: %s\n",
+ __func__, info->vreg[i].vreg_name);
+ else
+ dev_err(&info->i2c_client->dev, "%s %s ERR\n",
+ __func__, info->vreg[i].vreg_name);
+ }
+ info->vreg[i].vreg_flag = false;
+ return err;
+}
+
+static int ad5816_vreg_dis_all(struct ad5816_info *info)
+{
+ unsigned i;
+ int err = 0;
+ for (i = ARRAY_SIZE(ad5816_vregs); i > 0; i--)
+ err |= ad5816_vreg_dis(info, (i - 1));
+ return err;
+}
+
+static int ad5816_vreg_en(struct ad5816_info *info, ad5816_vreg i)
+{
+ int err = 0;
+ if (!info->vreg[i].vreg_flag && (info->vreg[i].vreg != NULL)) {
+ err = regulator_enable(info->vreg[i].vreg);
+
+ if (!err) {
+ dev_dbg(&info->i2c_client->dev, "%s: %s\n",
+ __func__, info->vreg[i].vreg_name);
+ info->vreg[i].vreg_flag = true;
+ err = 1; /* flag regulator state change */
+ } else {
+ dev_err(&info->i2c_client->dev, "%s %s ERR\n",
+ __func__, info->vreg[i].vreg_name);
+ }
+
+ }
+ return err;
+}
+
+static int ad5816_vreg_en_all(struct ad5816_info *info)
+{
+ unsigned i;
+ int err = 0;
+ for (i = 0; i < ARRAY_SIZE(ad5816_vregs); i++)
+ err |= ad5816_vreg_en(info, i);
+ return err;
+}
+
+static void ad5816_vreg_exit(struct ad5816_info *info)
+{
+ unsigned i;
+ for (i = 0; i < ARRAY_SIZE(ad5816_vregs); i++) {
+ regulator_put(info->vreg[i].vreg);
+ info->vreg[i].vreg = NULL;
+ }
+}
+
+static int ad5816_vreg_init(struct ad5816_info *info)
+{
+ unsigned i;
+ unsigned j;
+ int err = 0;
+ for (i = 0; i < ARRAY_SIZE(ad5816_vregs); i++) {
+ j = ad5816_vregs[i].vreg_num;
+ info->vreg[j].vreg_name = ad5816_vregs[i].vreg_name;
+ info->vreg[j].vreg_flag = false;
+ info->vreg[j].vreg = regulator_get(&info->i2c_client->dev,
+ info->vreg[j].vreg_name);
+ if (IS_ERR_OR_NULL(info->vreg[j].vreg)) {
+ dev_err(&info->i2c_client->dev, "%s %s ERR: %d\n",
+ __func__, info->vreg[j].vreg_name,
+ (int)info->vreg[j].vreg);
+ err |= PTR_ERR(info->vreg[j].vreg);
+ info->vreg[j].vreg = NULL;
+ } else {
+ dev_dbg(&info->i2c_client->dev, "%s: %s\n",
+ __func__, info->vreg[j].vreg_name);
+ }
+ }
+ return err;
+}
+
+void ad5816_set_power_down(struct ad5816_info *info)
+{
+ int err;
+ err = ad5816_i2c_wr16(info, VCM_CODE_MSB, 0x0000);
+ if (err)
+ dev_err(&info->i2c_client->dev, " %s: failed \n",
+ __func__);
+}
+
+void ad5816_set_arc_mode(struct ad5816_info *info)
+{
+ int err;
+ /* set ARC enable */
+ err = ad5816_i2c_wr8(info, CONTROL, 0x02);
+ if (err)
+ dev_err(&info->i2c_client->dev,
+ "%s: CONTROL reg write failed \n", __func__);
+
+ /* set the ARC RES2 */
+ err = ad5816_i2c_wr8(info, MODE, 0x01);
+ if (err)
+ dev_err(&info->i2c_client->dev,
+ "%s: MODE reg write failed \n", __func__);
+
+ /* set the VCM_FREQ to 12.8mS */
+ err = ad5816_i2c_wr8(info, VCM_FREQ, 0x80);
+ if (err)
+ dev_err(&info->i2c_client->dev,
+ "%s: VCM_FREQ reg write failed \n", __func__);
+}
+
+static int ad5816_pm_wr(struct ad5816_info *info, int pwr)
+{
+ int err = 0;
+
+ if ((info->pdata->cfg & (NVC_CFG_OFF2STDBY | NVC_CFG_BOOT_INIT)) &&
+ (pwr == NVC_PWR_OFF ||
+ pwr == NVC_PWR_STDBY_OFF))
+ pwr = NVC_PWR_STDBY;
+
+ if (pwr == info->pwr_dev)
+ return 0;
+
+ switch (pwr) {
+ case NVC_PWR_OFF_FORCE:
+ case NVC_PWR_OFF:
+ err = ad5816_vreg_dis_all(info);
+ ad5816_gpio_able(info, 0);
+ ad5816_gpio_reset(info, 0);
+ break;
+ case NVC_PWR_STDBY_OFF:
+ case NVC_PWR_STDBY:
+ err = ad5816_vreg_en_all(info);
+ ad5816_gpio_able(info, 1);
+ ad5816_gpio_reset(info, 1);
+ break;
+ case NVC_PWR_COMM:
+ case NVC_PWR_ON:
+ err = ad5816_vreg_en_all(info);
+ ad5816_gpio_able(info, 1);
+ ad5816_gpio_reset(info, 1);
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+
+ if (err < 0) {
+ dev_err(&info->i2c_client->dev, "%s err %d\n", __func__, err);
+ pwr = NVC_PWR_ERR;
+ }
+
+ info->pwr_dev = pwr;
+ dev_dbg(&info->i2c_client->dev, "%s pwr_dev=%d\n", __func__, info->pwr_dev);
+
+ if (err > 0)
+ return 0;
+
+ return err;
+}
+static int ad5816_pm_wr_s(struct ad5816_info *info, int pwr)
+{
+ int err1 = 0;
+ int err2 = 0;
+ if ((info->s_mode == NVC_SYNC_OFF) ||
+ (info->s_mode == NVC_SYNC_MASTER) ||
+ (info->s_mode == NVC_SYNC_STEREO))
+ err1 = ad5816_pm_wr(info, pwr);
+ if ((info->s_mode == NVC_SYNC_SLAVE) ||
+ (info->s_mode == NVC_SYNC_STEREO))
+ err2 = ad5816_pm_wr(info->s_info, pwr);
+ return err1 | err2;
+}
+
+static int ad5816_pm_api_wr(struct ad5816_info *info, int pwr)
+{
+ int err = 0;
+ if (!pwr || (pwr > NVC_PWR_ON))
+ return 0;
+ if (pwr > info->pwr_dev) {
+ err = ad5816_pm_wr_s(info, pwr);
+ }
+ if (!err) {
+ info->pwr_api = pwr;
+ } else {
+ info->pwr_api = NVC_PWR_ERR;
+ }
+ if (info->pdata->cfg & NVC_CFG_NOERR)
+ return 0;
+ return err;
+}
+
+static int ad5816_pm_dev_wr(struct ad5816_info *info, int pwr)
+{
+ if (pwr < info->pwr_api)
+ pwr = info->pwr_api;
+ return ad5816_pm_wr(info, pwr);
+}
+
+static void ad5816_pm_exit(struct ad5816_info *info)
+{
+ ad5816_pm_wr(info, NVC_PWR_OFF_FORCE);
+ ad5816_vreg_exit(info);
+ ad5816_gpio_exit(info);
+}
+static void ad5816_pm_init(struct ad5816_info *info)
+{
+ ad5816_gpio_init(info);
+ ad5816_vreg_init(info);
+}
+
+static int ad5816_reset(struct ad5816_info *info, u32 level)
+{
+ int err;
+ if (level == NVC_RESET_SOFT) {
+ err = ad5816_pm_wr(info, NVC_PWR_COMM);
+ err |= ad5816_i2c_wr8(info, CONTROL, 0x01); /* SW reset */
+ } else {
+ err = ad5816_pm_wr(info, NVC_PWR_OFF_FORCE);
+ }
+ err |= ad5816_pm_wr(info, info->pwr_api);
+ return err;
+}
+
+static int ad5816_dev_id(struct ad5816_info *info)
+{
+ u16 val = 0;
+ unsigned i;
+ int err;
+ ad5816_pm_dev_wr(info, NVC_PWR_COMM);
+ err = ad5816_i2c_rd16(info, IC_INFO, &val);
+ if (!err) {
+ dev_dbg(&info->i2c_client->dev, "%s found devId: %x\n", __func__, val);
+ info->id_minor = 0;
+ val = val & 0xff;
+ for (i = 0; i < ARRAY_SIZE(ad5816_ids); i++) {
+ if (val == ad5816_ids[i]) {
+ info->id_minor = val;
+ break;
+ }
+ }
+ if (!info->id_minor) {
+ err = -ENODEV;
+ dev_dbg(&info->i2c_client->dev, "%s No devId match\n", __func__);
+ }
+ }
+ ad5816_pm_dev_wr(info, NVC_PWR_OFF);
+ return err;
+}
+
+/**
+ * Below are device specific functions.
+ */
+
+static int ad5816_position_rd(struct ad5816_info *info, unsigned *position)
+{
+
+ u16 pos = 0;
+ u8 t1 = 0;
+ int err = 0;
+
+ err = ad5816_i2c_rd8(info, 0, VCM_CODE_MSB, &t1);
+ pos = t1 & 0x03;
+ err = ad5816_i2c_rd8(info, 0, VCM_CODE_LSB, &t1);
+ pos = (pos << 8) | t1;
+ if(pos)
+ *position = pos - info->config.pos_low;
+ else
+ *position = info->config.pos_low;
+
+ return 0;
+}
+
+static int ad5816_position_wr(struct ad5816_info *info, unsigned position)
+{
+ u16 data;
+
+ position = position + info->config.pos_low;
+ if(position > info->config.pos_high)
+ position = info->config.pos_high;
+
+ data = position & 0x03ff;
+
+ return ad5816_i2c_wr16(info, VCM_CODE_MSB, data);
+}
+
+static int ad5816_param_rd(struct ad5816_info *info, unsigned long arg)
+{
+ struct nvc_param params;
+ const void *data_ptr = NULL;
+ u32 data_size = 0;
+ u32 position;
+ int err;
+ if (copy_from_user(&params,
+ (const void __user *)arg,
+ sizeof(struct nvc_param))) {
+ dev_err(&info->i2c_client->dev, "%s %d copy_from_user err\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+ if (info->s_mode == NVC_SYNC_SLAVE)
+ info = info->s_info;
+ switch (params.param) {
+ case NVC_PARAM_LOCUS:
+ ad5816_pm_dev_wr(info, NVC_PWR_COMM);
+ err = ad5816_position_rd(info, &position);
+ if (err && !(info->pdata->cfg & NVC_CFG_NOERR))
+ return err;
+ data_ptr = &position;
+ data_size = sizeof(position);
+ ad5816_pm_dev_wr(info, NVC_PWR_STDBY);
+ dev_dbg(&info->i2c_client->dev, "%s LOCUS: %d\n",
+ __func__, position);
+ break;
+ case NVC_PARAM_FOCAL_LEN:
+ info->nvc.focal_length = AD5816_FOCAL_LENGTH;
+ data_ptr = &info->nvc.focal_length;
+ data_size = sizeof(info->nvc.focal_length);
+ break;
+ case NVC_PARAM_MAX_APERTURE:
+ data_ptr = &info->nvc.max_aperature;
+ data_size = sizeof(info->nvc.max_aperature);
+ dev_dbg(&info->i2c_client->dev, "%s MAX_APERTURE: %x\n",
+ __func__, info->nvc.max_aperature);
+ break;
+ case NVC_PARAM_FNUMBER:
+ data_ptr = &info->nvc.fnumber;
+ data_size = sizeof(info->nvc.fnumber);
+ dev_dbg(&info->i2c_client->dev, "%s FNUMBER: %u\n",
+ __func__, info->nvc.fnumber);
+ break;
+ case NVC_PARAM_CAPS:
+ data_ptr = &info->cap;
+ /* there are different sizes depending on the version */
+ /* send back just what's requested or our max size */
+ if (params.sizeofvalue < sizeof(info->cap))
+ data_size = params.sizeofvalue;
+ else
+ data_size = sizeof(info->cap);
+ dev_err(&info->i2c_client->dev, "%s CAPS\n", __func__);
+ break;
+ case NVC_PARAM_STS:
+ /*data_ptr = &info->sts;
+ data_size = sizeof(info->sts);*/
+ dev_dbg(&info->i2c_client->dev, "%s \n", __func__);
+ break;
+ case NVC_PARAM_STEREO:
+ data_ptr = &info->s_mode;
+ data_size = sizeof(info->s_mode);
+ dev_err(&info->i2c_client->dev, "%s STEREO: %d\n", __func__, info->s_mode);
+ break;
+ default:
+ dev_err(&info->i2c_client->dev, "%s unsupported parameter: %d\n",
+ __func__, params.param);
+ return -EINVAL;
+ }
+ if (params.sizeofvalue < data_size) {
+ dev_err(&info->i2c_client->dev,
+ "%s data size mismatch %d != %d Param: %d\n",
+ __func__, params.sizeofvalue, data_size, params.param);
+ return -EINVAL;
+ }
+ if (copy_to_user((void __user *)params.p_value, data_ptr, data_size)) {
+ dev_err(&info->i2c_client->dev, "%s copy_to_user err line %d\n",
+ __func__, __LINE__);
+ return -EFAULT;
+ }
+ return 0;
+}
+
+static int ad5816_param_wr_s(struct ad5816_info *info,
+ struct nvc_param *params, u32 u32val)
+{
+ int err = 0;
+ switch (params->param) {
+ case NVC_PARAM_LOCUS:
+ dev_dbg(&info->i2c_client->dev, "%s LOCUS: %u\n", __func__, u32val);
+ err = ad5816_position_wr(info, u32val);
+ return err;
+ case NVC_PARAM_RESET:
+ err = ad5816_reset(info, u32val);
+ dev_dbg(&info->i2c_client->dev, "%s RESET: %d\n", __func__, err);
+ return err;
+ case NVC_PARAM_SELF_TEST:
+ err = 0;
+ dev_dbg(&info->i2c_client->dev, "%s SELF_TEST: %d\n", __func__, err);
+ return err;
+ default:
+ dev_dbg(&info->i2c_client->dev,
+ "%s unsupported parameter: %d\n",
+ __func__, params->param);
+ return -EINVAL;
+ }
+}
+
+static int ad5816_param_wr(struct ad5816_info *info, unsigned long arg)
+{
+ struct nvc_param params;
+ u8 u8val;
+ u32 u32val;
+ int err = 0;
+ if (copy_from_user(&params, (const void __user *)arg,
+ sizeof(struct nvc_param))) {
+ dev_err(&info->i2c_client->dev, "%s copy_from_user err line %d\n",
+ __func__, __LINE__);
+ return -EFAULT;
+ }
+ if (copy_from_user(&u32val, (const void __user *)params.p_value, sizeof(u32val))) {
+ dev_err(&info->i2c_client->dev, "%s %d copy_from_user err\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+ u8val = (u8)u32val;
+ /* parameters independent of sync mode */
+ switch (params.param) {
+ case NVC_PARAM_STEREO:
+ dev_dbg(&info->i2c_client->dev, "%s STEREO: %d\n", __func__, u8val);
+ if (u8val == info->s_mode)
+ return 0;
+ switch (u8val) {
+ case NVC_SYNC_OFF:
+ info->s_mode = u8val;
+ ad5816_gpio_wr(info, AD5816_GPIO_I2CMUX, 0);
+ if (info->s_info != NULL) {
+ info->s_info->s_mode = u8val;
+ ad5816_pm_wr(info->s_info, NVC_PWR_OFF);
+ }
+ break;
+ case NVC_SYNC_MASTER:
+ info->s_mode = u8val;
+ ad5816_gpio_wr(info, AD5816_GPIO_I2CMUX, 0);
+ if (info->s_info != NULL)
+ info->s_info->s_mode = u8val;
+ break;
+ case NVC_SYNC_SLAVE:
+ if (info->s_info != NULL) {
+ /* default slave lens position */
+ err = ad5816_position_wr(info->s_info,
+ info->s_info->cap.focus_infinity);
+ if (!err) {
+ info->s_mode = u8val;
+ info->s_info->s_mode = u8val;
+ ad5816_gpio_wr(info,
+ AD5816_GPIO_I2CMUX, 0);
+ }
+ else {
+ if (info->s_mode != NVC_SYNC_STEREO)
+ ad5816_pm_wr(info->s_info,
+ NVC_PWR_OFF);
+ err = -EIO;
+ }
+ } else {
+ err = -EINVAL;
+ }
+ break;
+ case NVC_SYNC_STEREO:
+ if (info->s_info != NULL) {
+ /* sync power */
+ info->s_info->pwr_api = info->pwr_api;
+ /* move slave lens to master position */
+ err = ad5816_position_wr(info->s_info, info->pos);
+ if (!err) {
+ info->s_mode = u8val;
+ info->s_info->s_mode = u8val;
+ ad5816_gpio_wr(info, AD5816_GPIO_I2CMUX, 1);
+ }
+ else {
+ if (info->s_mode != NVC_SYNC_SLAVE)
+ ad5816_pm_wr(info->s_info, NVC_PWR_OFF);
+ err = -EIO;
+ }
+ } else {
+ err = -EINVAL;
+ }
+ break;
+ default:
+ err = -EINVAL;
+ }
+ if (info->pdata->cfg & NVC_CFG_NOERR)
+ return 0;
+ return err;
+ default:
+ /* parameters dependent on sync mode */
+ switch (info->s_mode) {
+ case NVC_SYNC_OFF:
+ case NVC_SYNC_MASTER:
+ return ad5816_param_wr_s(info, &params, u32val);
+ case NVC_SYNC_SLAVE:
+ return ad5816_param_wr_s(info->s_info, &params, u32val);
+ case NVC_SYNC_STEREO:
+ err = ad5816_param_wr_s(info, &params, u32val);
+ if (!(info->pdata->cfg & NVC_CFG_SYNC_I2C_MUX))
+ err |= ad5816_param_wr_s(info->s_info,
+ &params,
+ u32val);
+ return err;
+ default:
+ dev_err(&info->i2c_client->dev, "%s %d internal err\n",
+ __func__, __LINE__);
+ return -EINVAL;
+ }
+ }
+}
+
+static long ad5816_ioctl(struct file *file,
+ unsigned int cmd,
+ unsigned long arg)
+{
+ struct ad5816_info *info = file->private_data;
+ int pwr;
+ int err = 0;
+ switch (cmd) {
+ case NVC_IOCTL_PARAM_WR:
+ err = ad5816_param_wr(info, arg);
+ return err;
+ case NVC_IOCTL_PARAM_RD:
+ err = ad5816_param_rd(info, arg);
+ return err;
+ case NVC_IOCTL_PWR_WR:
+ /* This is a Guaranteed Level of Service (GLOS) call */
+ pwr = (int)arg * 2;
+ dev_dbg(&info->i2c_client->dev, "%s PWR_WR: %d\n",
+ __func__, pwr);
+ err = ad5816_pm_api_wr(info, pwr);
+ return err;
+ case NVC_IOCTL_PWR_RD:
+ if (info->s_mode == NVC_SYNC_SLAVE)
+ pwr = info->s_info->pwr_api / 2;
+ else
+ pwr = info->pwr_api / 2;
+ dev_dbg(&info->i2c_client->dev, "%s PWR_RD: %d\n",
+ __func__, pwr);
+ if (copy_to_user((void __user *)arg, (const void *)&pwr, sizeof(pwr))) {
+ dev_err(&info->i2c_client->dev, "%s copy_to_user err line %d\n",
+ __func__, __LINE__);
+ return -EFAULT;
+ }
+ return 0;
+ default:
+ dev_dbg(&info->i2c_client->dev, "%s unsupported ioctl: %x\n", __func__, cmd);
+ }
+ return -EINVAL;
+}
+
+
+static void ad5816_sdata_init(struct ad5816_info *info)
+{
+ /* set defaults */
+ memcpy(&info->config, &ad5816_default_info, sizeof(info->config));
+ memcpy(&info->nvc, &ad5816_default_nvc, sizeof(info->nvc));
+ memcpy(&info->cap, &ad5816_default_cap, sizeof(info->cap));
+
+ info->config.settle_time = AD5816_SETTLETIME;
+ info->config.focal_length = AD5816_FOCAL_LENGTH;
+ info->config.fnumber = AD5816_FNUMBER;
+ info->config.pos_low = AD5816_POS_LOW_DEFAULT;
+ info->config.pos_high = AD5816_POS_HIGH_DEFAULT;
+
+ /* set to proper value */
+ info->cap.actuator_range = info->config.pos_high - info->config.pos_low;
+
+ /* set overrides if any */
+ if (info->pdata->nvc) {
+ if (info->pdata->nvc->fnumber)
+ info->nvc.fnumber = info->pdata->nvc->fnumber;
+ if (info->pdata->nvc->focal_length)
+ info->nvc.focal_length = info->pdata->nvc->focal_length;
+ if (info->pdata->nvc->max_aperature)
+ info->nvc.max_aperature = info->pdata->nvc->max_aperature;
+ }
+
+ if (info->pdata->cap) {
+ if (info->pdata->cap->actuator_range)
+ info->cap.actuator_range = info->pdata->cap->actuator_range;
+ if (info->pdata->cap->settle_time)
+ info->cap.settle_time = info->pdata->cap->settle_time;
+ if (info->pdata->cap->focus_macro)
+ info->cap.focus_macro = info->pdata->cap->focus_macro;
+ if (info->pdata->cap->focus_hyper)
+ info->cap.focus_hyper = info->pdata->cap->focus_hyper;
+ if (info->pdata->cap->focus_infinity)
+ info->cap.focus_infinity = info->pdata->cap->focus_infinity;
+ }
+}
+
+static int ad5816_sync_en(unsigned num, unsigned sync)
+{
+ struct ad5816_info *master = NULL;
+ struct ad5816_info *slave = NULL;
+ struct ad5816_info *pos = NULL;
+ rcu_read_lock();
+ list_for_each_entry_rcu(pos, &ad5816_info_list, list) {
+ if (pos->pdata->num == num) {
+ master = pos;
+ break;
+ }
+ }
+ pos = NULL;
+ list_for_each_entry_rcu(pos, &ad5816_info_list, list) {
+ if (pos->pdata->num == sync) {
+ slave = pos;
+ break;
+ }
+ }
+ rcu_read_unlock();
+ if (master != NULL)
+ master->s_info = NULL;
+ if (slave != NULL)
+ slave->s_info = NULL;
+ if (!sync)
+ return 0; /* no err if sync disabled */
+ if (num == sync)
+ return -EINVAL; /* err if sync instance is itself */
+ if ((master != NULL) && (slave != NULL)) {
+ master->s_info = slave;
+ slave->s_info = master;
+ }
+ return 0;
+}
+
+static int ad5816_sync_dis(struct ad5816_info *info)
+{
+ if (info->s_info != NULL) {
+ info->s_info->s_mode = 0;
+ info->s_info->s_info = NULL;
+ info->s_mode = 0;
+ info->s_info = NULL;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static int ad5816_open(struct inode *inode, struct file *file)
+{
+ struct ad5816_info *info = NULL;
+ struct ad5816_info *pos = NULL;
+ int err;
+ rcu_read_lock();
+ list_for_each_entry_rcu(pos, &ad5816_info_list, list) {
+ if (pos->miscdev.minor == iminor(inode)) {
+ info = pos;
+ break;
+ }
+ }
+ rcu_read_unlock();
+ if (!info)
+ return -ENODEV;
+ err = ad5816_sync_en(info->pdata->num, info->pdata->sync);
+ if (err == -EINVAL)
+ dev_err(&info->i2c_client->dev, "%s err: invalid num (%u) and sync (%u) instance\n",
+ __func__, info->pdata->num, info->pdata->sync);
+ if (atomic_xchg(&info->in_use, 1))
+ return -EBUSY;
+ if (info->s_info != NULL) {
+ if (atomic_xchg(&info->s_info->in_use, 1))
+ return -EBUSY;
+ }
+ file->private_data = info;
+ ad5816_pm_dev_wr(info, NVC_PWR_ON);
+ /* set ARC Mode to ensure faster focus */
+ ad5816_set_arc_mode(info);
+ dev_dbg(&info->i2c_client->dev, "%s\n", __func__);
+
+ return 0;
+}
+
+static int ad5816_release(struct inode *inode, struct file *file)
+{
+ struct ad5816_info *info = file->private_data;
+ dev_dbg(&info->i2c_client->dev, "%s\n", __func__);
+ ad5816_pm_wr_s(info, NVC_PWR_OFF);
+ file->private_data = NULL;
+ WARN_ON(!atomic_xchg(&info->in_use, 0));
+ if (info->s_info != NULL)
+ WARN_ON(!atomic_xchg(&info->s_info->in_use, 0));
+ ad5816_sync_dis(info);
+ return 0;
+}
+
+static const struct file_operations ad5816_fileops = {
+ .owner = THIS_MODULE,
+ .open = ad5816_open,
+ .unlocked_ioctl = ad5816_ioctl,
+ .release = ad5816_release,
+};
+
+static void ad5816_del(struct ad5816_info *info)
+{
+ ad5816_pm_exit(info);
+ if ((info->s_mode == NVC_SYNC_SLAVE) ||
+ (info->s_mode == NVC_SYNC_STEREO))
+ ad5816_pm_exit(info->s_info);
+
+ ad5816_sync_dis(info);
+ spin_lock(&ad5816_spinlock);
+ list_del_rcu(&info->list);
+ spin_unlock(&ad5816_spinlock);
+ synchronize_rcu();
+}
+
+static int ad5816_remove(struct i2c_client *client)
+{
+ struct ad5816_info *info = i2c_get_clientdata(client);
+ dev_dbg(&info->i2c_client->dev, "%s\n", __func__);
+ misc_deregister(&info->miscdev);
+ ad5816_del(info);
+ return 0;
+}
+
+static int ad5816_probe(
+ struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct ad5816_info *info;
+ char dname[16];
+ int err;
+
+ pr_info("ad5816: probing focuser.\n");
+ dev_dbg(&client->dev, "%s\n", __func__);
+ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL);
+ if (info == NULL) {
+ dev_err(&client->dev, "%s: kzalloc error\n", __func__);
+ return -ENOMEM;
+ }
+ info->i2c_client = client;
+ if (client->dev.platform_data) {
+ info->pdata = client->dev.platform_data;
+ } else {
+ info->pdata = &ad5816_default_pdata;
+ dev_dbg(&client->dev,"%s No platform data. Using defaults.\n", __func__);
+ }
+
+ i2c_set_clientdata(client, info);
+ INIT_LIST_HEAD(&info->list);
+ spin_lock(&ad5816_spinlock);
+ list_add_rcu(&info->list, &ad5816_info_list);
+ spin_unlock(&ad5816_spinlock);
+ ad5816_pm_init(info);
+ ad5816_sdata_init(info);
+
+ if (info->pdata->cfg & (NVC_CFG_NODEV | NVC_CFG_BOOT_INIT)) {
+ err = ad5816_dev_id(info);
+ if (err < 0) {
+ dev_err(&client->dev, "%s device not found\n", __func__);
+ ad5816_pm_wr(info, NVC_PWR_OFF);
+ if (info->pdata->cfg & NVC_CFG_NODEV) {
+ ad5816_del(info);
+ return -ENODEV;
+ }
+ } else {
+ dev_dbg(&client->dev, "%s device found\n", __func__);
+ if (info->pdata->cfg & NVC_CFG_BOOT_INIT) {
+ /* initial move causes full initialization */
+ ad5816_pm_dev_wr(info, NVC_PWR_ON);
+ ad5816_position_wr(info, info->cap.focus_infinity);
+ ad5816_pm_dev_wr(info, NVC_PWR_OFF);
+ }
+ }
+ }
+
+ if (info->pdata->dev_name != 0)
+ strcpy(dname, info->pdata->dev_name);
+ else
+ strcpy(dname, "ad5816");
+
+ if (info->pdata->num)
+ snprintf(dname, sizeof(dname), "%s.%u", dname, info->pdata->num);
+
+ info->miscdev.name = dname;
+ info->miscdev.fops = &ad5816_fileops;
+ info->miscdev.minor = MISC_DYNAMIC_MINOR;
+ if (misc_register(&info->miscdev)) {
+ dev_err(&client->dev, "%s unable to register misc device %s\n",
+ __func__, dname);
+ ad5816_del(info);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+
+static const struct i2c_device_id ad5816_id[] = {
+ { "ad5816", 0 },
+ { },
+};
+
+
+MODULE_DEVICE_TABLE(i2c, ad5816_id);
+
+static struct i2c_driver ad5816_i2c_driver = {
+ .driver = {
+ .name = "ad5816",
+ .owner = THIS_MODULE,
+ },
+ .id_table = ad5816_id,
+ .probe = ad5816_probe,
+ .remove = ad5816_remove,
+};
+
+static int __init ad5816_init(void)
+{
+ return i2c_add_driver(&ad5816_i2c_driver);
+}
+
+static void __exit ad5816_exit(void)
+{
+ i2c_del_driver(&ad5816_i2c_driver);
+}
+
+module_init(ad5816_init);
+module_exit(ad5816_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/tegra/ar0832_main.c b/drivers/media/video/tegra/ar0832_main.c
index f3b56bbf847e..4da9f7e833b9 100644
--- a/drivers/media/video/tegra/ar0832_main.c
+++ b/drivers/media/video/tegra/ar0832_main.c
@@ -23,9 +23,11 @@
#include <linux/regulator/consumer.h>
#include <media/ar0832_main.h>
-#define POS_LOW 0
-#define POS_HIGH 1000
-#define SETTLETIME_MS 100
+#define POS_ACTUAL_LOW 0
+#define POS_ACTUAL_HIGH 255
+#define SETTLE_TIME 100
+#define SLEW_RATE_DEFAULT 1
+
struct ar0832_sensor_info {
int mode;
@@ -33,7 +35,7 @@ struct ar0832_sensor_info {
};
struct ar0832_focuser_info {
- struct ar0832_focuser_config config;
+ struct nv_focuser_config config;
int focuser_init_flag;
u16 last_position;
};
@@ -142,7 +144,7 @@ static struct ar0832_reg mode_3264X2448_8140[] = {
{0x3E12, 0x4B24},
{0x3E14, 0xA3CF},
{0x3E16, 0x8802},
- {0x3E18, 0x8401},
+ {0x3E18, 0x84FF},
{0x3E1A, 0x8601},
{0x3E1C, 0x8401},
{0x3E1E, 0x840A},
@@ -190,7 +192,6 @@ static struct ar0832_reg mode_3264X2448_8140[] = {
{0x3ED4, 0xAFC4},
{0x3ED6, 0x909B},
{0x3EE0, 0x2424},
- {0x3EE2, 0x9797},
{0x3EE4, 0xC100},
{0x3EE6, 0x0540},
{0x3174, 0x8000},
@@ -246,8 +247,8 @@ static struct ar0832_reg mode_3264X2448_8141[] = {
{0x306E, 0xFC80},
{0x30B2, 0xC000},
{0x30D6, 0x0800},
- {0x316C, 0xB42F},
- {0x316E, 0x869A},
+ {0x316C, 0xB42A},
+ {0x316E, 0x869C},
{0x3170, 0x210E},
{0x317A, 0x010E},
{0x31E0, 0x1FB9},
@@ -278,7 +279,7 @@ static struct ar0832_reg mode_3264X2448_8141[] = {
{0x3E26, 0x0088},
{0x3E28, 0x2E8A},
{0x3E30, 0x0000},
- {0x3E32, 0x8801},
+ {0x3E32, 0x00FF},
{0x3E34, 0x4029},
{0x3E36, 0x00FF},
{0x3E38, 0x8469},
@@ -308,15 +309,14 @@ static struct ar0832_reg mode_3264X2448_8141[] = {
{0x3E98, 0x2B02},
{0x3E92, 0x2A04},
{0x3E94, 0x2509},
- {0x3E96, 0x0000},
+ {0x3E96, 0xF000},
{0x3E9A, 0x2905},
{0x3E9C, 0x00FF},
{0x3ECC, 0x00EB},
{0x3ED0, 0x1E24},
- {0x3ED4, 0xAFC4},
+ {0x3ED4, 0xFAA4},
{0x3ED6, 0x909B},
{0x3EE0, 0x2424},
- {0x3EE2, 0x9797},
{0x3EE4, 0xC100},
{0x3EE6, 0x0540},
{0x3174, 0x8000},
@@ -2160,7 +2160,8 @@ static long ar0832_ioctl(struct file *file,
"%s AR0832_FOCUSER_IOCTL_GET_CONFIG\n", __func__);
if (copy_to_user((void __user *) arg,
&dev->focuser_info->config,
- sizeof(dev->focuser_info->config))) {
+ sizeof(struct nv_focuser_config)))
+ {
dev_err(&i2c_client->dev,
"%s: AR0832_FOCUSER_IOCTL_GET_CONFIG failed\n",
__func__);
@@ -2168,6 +2169,25 @@ static long ar0832_ioctl(struct file *file,
}
return 0;
+ case AR0832_FOCUSER_IOCTL_SET_CONFIG:
+ dev_info(&i2c_client->dev,
+ "%s AR0832_FOCUSER_IOCTL_SET_CONFIG\n", __func__);
+ if (copy_from_user(&dev->focuser_info->config,
+ (const void __user *)arg,
+ sizeof(struct nv_focuser_config)))
+ {
+ dev_err(&i2c_client->dev,
+ "%s: AR0832_FOCUSER_IOCTL_SET_CONFIG failed\n", __func__);
+ return -EFAULT;
+ }
+ dev_dbg(&i2c_client->dev,
+ "%s AR0832_FOCUSER_IOCTL_SET_CONFIG sucess "
+ "slew_rate %i, pos_working_high %i, pos_working_low %i\n",
+ __func__, dev->focuser_info->config.slew_rate,
+ dev->focuser_info->config.pos_working_low,
+ dev->focuser_info->config.pos_working_high);
+ return 0;
+
case AR0832_FOCUSER_IOCTL_SET_POSITION:
dev_dbg(&i2c_client->dev,
"%s AR0832_FOCUSER_IOCTL_SET_POSITION\n", __func__);
@@ -2443,9 +2463,12 @@ static int ar0832_probe(struct i2c_client *client,
dev->i2c_client = client;
/* focuser */
- dev->focuser_info->config.settle_time = SETTLETIME_MS;
- dev->focuser_info->config.pos_low = POS_LOW;
- dev->focuser_info->config.pos_high = POS_HIGH;
+ dev->focuser_info->config.settle_time = SETTLE_TIME;
+ dev->focuser_info->config.slew_rate = SLEW_RATE_DEFAULT;
+ dev->focuser_info->config.pos_actual_low = POS_ACTUAL_LOW;
+ dev->focuser_info->config.pos_actual_high = POS_ACTUAL_HIGH;
+ dev->focuser_info->config.pos_working_low = POS_ACTUAL_LOW;
+ dev->focuser_info->config.pos_working_high = POS_ACTUAL_HIGH;
snprintf(dev->dname, sizeof(dev->dname), "%s-%s",
id->name, dev->pdata->id);
diff --git a/drivers/media/video/tegra/avp/avp.c b/drivers/media/video/tegra/avp/avp.c
index 074a42f125be..fc965e4f5b53 100644
--- a/drivers/media/video/tegra/avp/avp.c
+++ b/drivers/media/video/tegra/avp/avp.c
@@ -42,7 +42,7 @@
#include <mach/clk.h>
#include <mach/io.h>
#include <mach/iomap.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include <mach/legacy_irq.h>
#include <mach/hardware.h>
diff --git a/drivers/media/video/tegra/avp/avp_svc.c b/drivers/media/video/tegra/avp/avp_svc.c
index 17c8b8535a62..4063ac17e570 100644
--- a/drivers/media/video/tegra/avp/avp_svc.c
+++ b/drivers/media/video/tegra/avp/avp_svc.c
@@ -29,7 +29,7 @@
#include <linux/types.h>
#include <mach/clk.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include "../../../../video/tegra/nvmap/nvmap.h"
@@ -464,7 +464,7 @@ static void do_svc_module_clock_set(struct avp_svc_info *avp_svc,
struct svc_clock_ctrl *msg = (struct svc_clock_ctrl *)_msg;
struct svc_clock_ctrl_response resp;
struct avp_module *mod;
- struct avp_clk *aclk;
+ struct avp_clk *aclk = NULL;
int ret = 0;
mod = find_avp_module(avp_svc, msg->module_id);
diff --git a/drivers/media/video/tegra/nvavp/Kconfig b/drivers/media/video/tegra/nvavp/Kconfig
index 2d3af3f79fb3..294253a0de49 100644
--- a/drivers/media/video/tegra/nvavp/Kconfig
+++ b/drivers/media/video/tegra/nvavp/Kconfig
@@ -8,3 +8,14 @@ config TEGRA_NVAVP
/dev/tegra_avpchannel.
If unsure, say N
+
+config TEGRA_NVAVP_AUDIO
+ bool "Enable Audio Channel support for Tegra NVAVP driver"
+ depends on TEGRA_NVAVP
+ default n
+ help
+ Enables support for the push-buffer mechanism based driver for the Tegra
+ audio multimedia framework. Exports the Tegra nvavp interface on device node
+ /dev/tegra_audio_avpchannel.
+
+ If unsure, say N
diff --git a/drivers/media/video/tegra/nvavp/Makefile b/drivers/media/video/tegra/nvavp/Makefile
index 82b4238fd085..af2659e84664 100644
--- a/drivers/media/video/tegra/nvavp/Makefile
+++ b/drivers/media/video/tegra/nvavp/Makefile
@@ -1,3 +1,5 @@
GCOV_PROFILE := y
+EXTRA_CFLAGS += -Idrivers/video/tegra/host
+
obj-$(CONFIG_TEGRA_NVAVP) += nvavp_dev.o
obj-$(CONFIG_TEGRA_AVP_KERNEL_ON_MMU) += ../avp/headavp.o
diff --git a/drivers/media/video/tegra/nvavp/nvavp_dev.c b/drivers/media/video/tegra/nvavp/nvavp_dev.c
index 3741043eb1d2..9a54f8e3d025 100644
--- a/drivers/media/video/tegra/nvavp/nvavp_dev.c
+++ b/drivers/media/video/tegra/nvavp/nvavp_dev.c
@@ -40,12 +40,7 @@
#include <mach/io.h>
#include <mach/iomap.h>
#include <mach/legacy_irq.h>
-#include <mach/nvmap.h>
-
-#include "../../../../video/tegra/nvmap/nvmap.h"
-#include "../../../../video/tegra/host/host1x/host1x_syncpt.h"
-#include "../../../../video/tegra/host/dev.h"
-#include "../../../../video/tegra/host/nvhost_acm.h"
+#include <linux/nvmap.h>
#if defined(CONFIG_TEGRA_AVP_KERNEL_ON_MMU)
#include "../avp/headavp.h"
@@ -73,6 +68,34 @@
/* AVP behavior params */
#define NVAVP_OS_IDLE_TIMEOUT 100 /* milli-seconds */
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+/* Two control channels: Audio and Video channels */
+#define NVAVP_NUM_CHANNELS 2
+
+#define NVAVP_AUDIO_CHANNEL 1
+
+#define IS_AUDIO_CHANNEL_ID(channel_id) (channel_id == NVAVP_AUDIO_CHANNEL ? 1: 0)
+#else
+#define NVAVP_NUM_CHANNELS 1
+#endif
+
+/* Channel ID 0 represents the Video channel control area */
+#define NVAVP_VIDEO_CHANNEL 0
+/* Channel ID 1 represents the Audio channel control area */
+
+#define IS_VIDEO_CHANNEL_ID(channel_id) (channel_id == NVAVP_VIDEO_CHANNEL ? 1: 0)
+
+
+struct nvavp_channel {
+ struct mutex pushbuffer_lock;
+ struct nvmap_handle_ref *pushbuf_handle;
+ unsigned long pushbuf_phys;
+ u8 *pushbuf_data;
+ u32 pushbuf_index;
+ u32 pushbuf_fence;
+ struct nv_e276_control *os_control;
+};
+
struct nvavp_info {
u32 clk_enabled;
struct clk *bsev_clk;
@@ -89,8 +112,10 @@ struct nvavp_info {
struct mutex open_lock;
int refcount;
- int initialized;
-
+ int video_initialized;
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ int audio_initialized;
+#endif
struct work_struct clock_disable_work;
/* os information */
@@ -102,22 +127,18 @@ struct nvavp_info {
/* client for driver allocations, persistent */
struct nvmap_client *nvmap;
- struct mutex pushbuffer_lock;
- struct nvmap_handle_ref *pushbuf_handle;
- unsigned long pushbuf_phys;
- u8 *pushbuf_data;
- u32 pushbuf_index;
- u32 pushbuf_fence;
+ bool pending;
- struct nv_e276_control *os_control;
+ struct nvavp_channel channel_info[NVAVP_NUM_CHANNELS];
- struct nvhost_syncpt *nvhost_syncpt;
u32 syncpt_id;
u32 syncpt_value;
struct nvhost_device *nvhost_dev;
- struct miscdevice misc_dev;
- atomic_t clock_stay_on_refcount;
+ struct miscdevice video_misc_dev;
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ struct miscdevice audio_misc_dev;
+#endif
};
struct nvavp_clientctx {
@@ -127,9 +148,78 @@ struct nvavp_clientctx {
struct nvmap_handle_ref *gather_mem;
int num_relocs;
struct nvavp_info *nvavp;
- int clock_stay_on;
+ u32 clk_reqs;
+ int channel_id;
};
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+static int nvavp_get_audio_init_status(struct nvavp_info *nvavp)
+{
+ return nvavp->audio_initialized;
+}
+
+static void nvavp_set_audio_init_status(struct nvavp_info *nvavp, int status)
+{
+ nvavp->audio_initialized = status;
+}
+#endif
+
+static void nvavp_set_video_init_status(struct nvavp_info *nvavp, int status)
+{
+ nvavp->video_initialized = status;
+}
+
+static int nvavp_get_video_init_status(struct nvavp_info *nvavp)
+{
+ return nvavp->video_initialized;
+}
+
+static struct nvavp_channel *nvavp_get_channel_info(struct nvavp_info *nvavp, int channel_id)
+{
+ return &nvavp->channel_info[channel_id];
+}
+
+static void nvavp_set_channel_control_area(struct nvavp_info *nvavp, int channel_id)
+{
+ struct nv_e276_control *control;
+ struct nvavp_os_info *os = &nvavp->os_info;
+ u32 temp;
+ void *ptr;
+ struct nvavp_channel *channel_info;
+
+ ptr = os->data + os->control_offset + (sizeof(struct nv_e276_control) * channel_id);
+
+ channel_info = nvavp_get_channel_info(nvavp, channel_id);
+ channel_info->os_control = (struct nv_e276_control *)ptr;
+
+ control = channel_info->os_control;
+
+ /* init get and put pointers */
+ writel(0x0, &control->put);
+ writel(0x0, &control->get);
+
+ pr_debug("nvavp_set_channel_control_area for channel_id (%d):\
+ control->put (0x%08x) control->get (0x%08x)\n",
+ channel_id, (u32) &control->put, (u32) &control->get);
+
+ /* enable avp VDE clock control and disable iram clock gating */
+ writel(0x0, &control->idle_clk_enable);
+ writel(0x0, &control->iram_clk_gating);
+
+ /* enable avp idle timeout interrupt */
+ writel(0x1, &control->idle_notify_enable);
+ writel(NVAVP_OS_IDLE_TIMEOUT, &control->idle_notify_delay);
+
+ /* init dma start and end pointers */
+ writel(channel_info->pushbuf_phys, &control->dma_start);
+ writel((channel_info->pushbuf_phys + NVAVP_PUSHBUFFER_SIZE),
+ &control->dma_end);
+
+ writel(0x00, &channel_info->pushbuf_index);
+ temp = NVAVP_PUSHBUFFER_SIZE - NVAVP_PUSHBUFFER_MIN_UPDATE_SPACE;
+ writel(temp, &channel_info->pushbuf_fence);
+}
+
static struct clk *nvavp_clk_get(struct nvavp_info *nvavp, int id)
{
if (!nvavp)
@@ -145,26 +235,29 @@ static struct clk *nvavp_clk_get(struct nvavp_info *nvavp, int id)
return NULL;
}
-static void nvavp_clk_ctrl(struct nvavp_info *nvavp, u32 clk_en)
+static void nvavp_clks_enable(struct nvavp_info *nvavp)
{
- if (clk_en && !nvavp->clk_enabled) {
- nvhost_module_busy(nvhost_get_host(nvavp->nvhost_dev)->dev);
+ if (nvavp->clk_enabled++ == 0) {
+ nvhost_module_busy_ext(nvhost_get_parent(nvavp->nvhost_dev));
clk_enable(nvavp->bsev_clk);
clk_enable(nvavp->vde_clk);
clk_set_rate(nvavp->emc_clk, nvavp->emc_clk_rate);
clk_set_rate(nvavp->sclk, nvavp->sclk_rate);
- nvavp->clk_enabled = 1;
dev_dbg(&nvavp->nvhost_dev->dev, "%s: setting sclk to %lu\n",
__func__, nvavp->sclk_rate);
dev_dbg(&nvavp->nvhost_dev->dev, "%s: setting emc_clk to %lu\n",
__func__, nvavp->emc_clk_rate);
- } else if (!clk_en && nvavp->clk_enabled) {
+ }
+}
+
+static void nvavp_clks_disable(struct nvavp_info *nvavp)
+{
+ if (--nvavp->clk_enabled == 0) {
clk_disable(nvavp->bsev_clk);
clk_disable(nvavp->vde_clk);
clk_set_rate(nvavp->emc_clk, 0);
clk_set_rate(nvavp->sclk, 0);
- nvhost_module_idle(nvhost_get_host(nvavp->nvhost_dev)->dev);
- nvavp->clk_enabled = 0;
+ nvhost_module_idle_ext(nvhost_get_parent(nvavp->nvhost_dev));
dev_dbg(&nvavp->nvhost_dev->dev, "%s: resetting emc_clk "
"and sclk\n", __func__);
}
@@ -172,21 +265,29 @@ static void nvavp_clk_ctrl(struct nvavp_info *nvavp, u32 clk_en)
static u32 nvavp_check_idle(struct nvavp_info *nvavp)
{
- struct nv_e276_control *control = nvavp->os_control;
- return ((control->put == control->get)
- && (!atomic_read(&nvavp->clock_stay_on_refcount))) ? 1 : 0;
+ struct nvavp_channel *channel_info = nvavp_get_channel_info(nvavp, NVAVP_VIDEO_CHANNEL);
+ struct nv_e276_control *control = channel_info->os_control;
+
+ return (control->put == control->get) ? 1 : 0;
}
static void clock_disable_handler(struct work_struct *work)
{
struct nvavp_info *nvavp;
+ struct nvavp_channel *channel_info;
nvavp = container_of(work, struct nvavp_info,
clock_disable_work);
+ channel_info = nvavp_get_channel_info(nvavp, NVAVP_VIDEO_CHANNEL);
- mutex_lock(&nvavp->pushbuffer_lock);
- nvavp_clk_ctrl(nvavp, !nvavp_check_idle(nvavp));
- mutex_unlock(&nvavp->pushbuffer_lock);
+ mutex_lock(&channel_info->pushbuffer_lock);
+ mutex_lock(&nvavp->open_lock);
+ if (nvavp_check_idle(nvavp) && nvavp->pending) {
+ nvavp->pending = false;
+ nvavp_clks_disable(nvavp);
+ }
+ mutex_unlock(&nvavp->open_lock);
+ mutex_unlock(&channel_info->pushbuffer_lock);
}
static int nvavp_service(struct nvavp_info *nvavp)
@@ -199,11 +300,13 @@ static int nvavp_service(struct nvavp_info *nvavp)
if (!(inbox & NVAVP_INBOX_VALID))
inbox = 0x00000000;
- writel(0x00000000, NVAVP_OS_INBOX);
-
if (inbox & NVE276_OS_INTERRUPT_VIDEO_IDLE)
schedule_work(&nvavp->clock_disable_work);
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ if (inbox & NVE276_OS_INTERRUPT_AUDIO_IDLE)
+ pr_debug("nvavp_service NVE276_OS_INTERRUPT_AUDIO_IDLE\n");
+#endif
if (inbox & NVE276_OS_INTERRUPT_DEBUG_STRING) {
/* Should only occur with debug AVP OS builds */
debug_print = os->data;
@@ -223,6 +326,7 @@ static int nvavp_service(struct nvavp_info *nvavp)
dev_err(&nvavp->nvhost_dev->dev, "AVP breakpoint hit\n");
if (inbox & NVE276_OS_INTERRUPT_TIMEOUT)
dev_err(&nvavp->nvhost_dev->dev, "AVP timeout\n");
+ writel(inbox & NVAVP_INBOX_VALID, NVAVP_OS_INBOX);
return 0;
}
@@ -290,27 +394,29 @@ static int nvavp_reset_avp(struct nvavp_info *nvavp, unsigned long reset_addr)
static void nvavp_halt_vde(struct nvavp_info *nvavp)
{
- if (nvavp->clk_enabled) {
- tegra_periph_reset_assert(nvavp->bsev_clk);
- clk_disable(nvavp->bsev_clk);
- tegra_periph_reset_assert(nvavp->vde_clk);
- clk_disable(nvavp->vde_clk);
- nvhost_module_idle(nvhost_get_host(nvavp->nvhost_dev)->dev);
- nvavp->clk_enabled = 0;
+ if (nvavp->clk_enabled && !nvavp->pending)
+ BUG();
+
+ if (nvavp->pending) {
+ nvavp_clks_disable(nvavp);
+ nvavp->pending = false;
}
+
+ tegra_periph_reset_assert(nvavp->bsev_clk);
+ tegra_periph_reset_assert(nvavp->vde_clk);
}
static int nvavp_reset_vde(struct nvavp_info *nvavp)
{
- if (!nvavp->clk_enabled)
- nvhost_module_busy(nvhost_get_host(nvavp->nvhost_dev)->dev);
+ if (nvavp->clk_enabled)
+ BUG();
+
+ nvavp_clks_enable(nvavp);
- clk_enable(nvavp->bsev_clk);
tegra_periph_reset_assert(nvavp->bsev_clk);
udelay(2);
tegra_periph_reset_deassert(nvavp->bsev_clk);
- clk_enable(nvavp->vde_clk);
tegra_periph_reset_assert(nvavp->vde_clk);
udelay(2);
tegra_periph_reset_deassert(nvavp->vde_clk);
@@ -322,103 +428,95 @@ static int nvavp_reset_vde(struct nvavp_info *nvavp)
*/
clk_set_rate(nvavp->vde_clk, ULONG_MAX);
- nvavp->clk_enabled = 1;
+ nvavp_clks_disable(nvavp);
+
return 0;
}
-static int nvavp_pushbuffer_alloc(struct nvavp_info *nvavp)
+static int nvavp_pushbuffer_alloc(struct nvavp_info *nvavp, int channel_id)
{
int ret = 0;
- nvavp->pushbuf_handle = nvmap_alloc(nvavp->nvmap, NVAVP_PUSHBUFFER_SIZE,
- SZ_1M, NVMAP_HANDLE_UNCACHEABLE, 0);
- if (IS_ERR(nvavp->pushbuf_handle)) {
+ struct nvavp_channel *channel_info = nvavp_get_channel_info(
+ nvavp, channel_id);
+
+ channel_info->pushbuf_handle = nvmap_alloc(nvavp->nvmap,
+ NVAVP_PUSHBUFFER_SIZE,
+ SZ_1M, NVMAP_HANDLE_UNCACHEABLE,
+ 0);
+ if (IS_ERR(channel_info->pushbuf_handle)) {
dev_err(&nvavp->nvhost_dev->dev,
"cannot create pushbuffer handle\n");
- ret = PTR_ERR(nvavp->pushbuf_handle);
+ ret = PTR_ERR(channel_info->pushbuf_handle);
goto err_pushbuf_alloc;
}
- nvavp->pushbuf_data = (u8 *)nvmap_mmap(nvavp->pushbuf_handle);
- if (!nvavp->pushbuf_data) {
+ channel_info->pushbuf_data = (u8 *)nvmap_mmap(
+ channel_info->pushbuf_handle);
+
+ if (!channel_info->pushbuf_data) {
dev_err(&nvavp->nvhost_dev->dev,
"cannot map pushbuffer handle\n");
ret = -ENOMEM;
goto err_pushbuf_mmap;
}
- nvavp->pushbuf_phys = nvmap_pin(nvavp->nvmap, nvavp->pushbuf_handle);
- if (IS_ERR((void *)nvavp->pushbuf_phys)) {
+ channel_info->pushbuf_phys = nvmap_pin(nvavp->nvmap,
+ channel_info->pushbuf_handle);
+ if (IS_ERR((void *)channel_info->pushbuf_phys)) {
dev_err(&nvavp->nvhost_dev->dev,
"cannot pin pushbuffer handle\n");
- ret = PTR_ERR((void *)nvavp->pushbuf_phys);
+ ret = PTR_ERR((void *)channel_info->pushbuf_phys);
goto err_pushbuf_pin;
}
- memset(nvavp->pushbuf_data, 0, NVAVP_PUSHBUFFER_SIZE);
+ memset(channel_info->pushbuf_data, 0, NVAVP_PUSHBUFFER_SIZE);
return 0;
err_pushbuf_pin:
- nvmap_munmap(nvavp->pushbuf_handle, nvavp->pushbuf_data);
+ nvmap_munmap(channel_info->pushbuf_handle, channel_info->pushbuf_data);
err_pushbuf_mmap:
- nvmap_free(nvavp->nvmap, nvavp->pushbuf_handle);
+ nvmap_free(nvavp->nvmap, channel_info->pushbuf_handle);
err_pushbuf_alloc:
return ret;
}
static void nvavp_pushbuffer_free(struct nvavp_info *nvavp)
{
- nvmap_unpin(nvavp->nvmap, nvavp->pushbuf_handle);
- nvmap_munmap(nvavp->pushbuf_handle, nvavp->pushbuf_data);
- nvmap_free(nvavp->nvmap, nvavp->pushbuf_handle);
+ int channel_id;
+
+ for (channel_id = 0; channel_id < NVAVP_NUM_CHANNELS; channel_id++) {
+ if (nvavp->channel_info[channel_id].pushbuf_data) {
+ nvmap_unpin(nvavp->nvmap,
+ nvavp->channel_info[channel_id].pushbuf_handle);
+ nvmap_munmap(
+ nvavp->channel_info[channel_id].pushbuf_handle,
+ nvavp->channel_info[channel_id].pushbuf_data);
+ nvmap_free(nvavp->nvmap,
+ nvavp->channel_info[channel_id].pushbuf_handle);
+ }
+ }
}
+
static int nvavp_pushbuffer_init(struct nvavp_info *nvavp)
{
- void *ptr;
- struct nvavp_os_info *os = &nvavp->os_info;
- struct nv_e276_control *control;
- u32 temp;
- int ret;
-
- ret = nvavp_pushbuffer_alloc(nvavp);
- if (ret) {
- dev_err(&nvavp->nvhost_dev->dev,
- "unable to alloc pushbuffer\n");
- return ret;
- }
+ int ret, channel_id;
- ptr = os->data;
- ptr += os->control_offset;
- nvavp->os_control = (struct nv_e276_control *)ptr;
-
- control = nvavp->os_control;
- memset(control, 0, sizeof(struct nvavp_os_info));
-
- /* init get and put pointers */
- writel(0x0, &control->put);
- writel(0x0, &control->get);
-
- /* enable avp VDE clock control and disable iram clock gating */
- writel(0x0, &control->idle_clk_enable);
- writel(0x0, &control->iram_clk_gating);
-
- /* enable avp idle timeout interrupt */
- writel(0x1, &control->idle_notify_enable);
- writel(NVAVP_OS_IDLE_TIMEOUT, &control->idle_notify_delay);
-
- /* init dma start and end pointers */
- writel(nvavp->pushbuf_phys, &control->dma_start);
- writel((nvavp->pushbuf_phys + NVAVP_PUSHBUFFER_SIZE),
- &control->dma_end);
-
- writel(0x00, &nvavp->pushbuf_index);
- temp = NVAVP_PUSHBUFFER_SIZE - NVAVP_PUSHBUFFER_MIN_UPDATE_SPACE;
- writel(temp, &nvavp->pushbuf_fence);
-
- nvavp->syncpt_id = NVSYNCPT_AVP_0;
- nvavp->syncpt_value = nvhost_syncpt_read(nvavp->nvhost_syncpt,
- nvavp->syncpt_id);
+ for (channel_id = 0; channel_id < NVAVP_NUM_CHANNELS; channel_id++) {
+ ret = nvavp_pushbuffer_alloc(nvavp, channel_id);
+ if (ret) {
+ dev_err(&nvavp->nvhost_dev->dev,
+ "unable to alloc pushbuffer\n");
+ return ret;
+ }
+ nvavp_set_channel_control_area(nvavp, channel_id);
+ if (IS_VIDEO_CHANNEL_ID(channel_id)) {
+ nvavp->syncpt_id = NVSYNCPT_AVP_0;
+ nvavp->syncpt_value = nvhost_syncpt_read_ext(
+ nvavp->nvhost_dev, nvavp->syncpt_id);
+ }
+ }
return 0;
}
@@ -429,37 +527,47 @@ static void nvavp_pushbuffer_deinit(struct nvavp_info *nvavp)
static int nvavp_pushbuffer_update(struct nvavp_info *nvavp, u32 phys_addr,
u32 gather_count, struct nvavp_syncpt *syncpt,
- u32 ext_ucode_flag)
+ u32 ext_ucode_flag, int channel_id)
{
- struct nv_e276_control *control = nvavp->os_control;
+ struct nvavp_channel *channel_info;
+ struct nv_e276_control *control;
u32 gather_cmd, setucode_cmd, sync = 0;
u32 wordcount = 0;
u32 index, value = -1;
- mutex_lock(&nvavp->pushbuffer_lock);
+ channel_info = nvavp_get_channel_info(nvavp, channel_id);
+
+ control = channel_info->os_control;
+ pr_debug("nvavp_pushbuffer_update for channel_id (%d):\
+ control->put (0x%x) control->get (0x%x)\n",
+ channel_id, (u32) &control->put, (u32) &control->get);
+
+ mutex_lock(&channel_info->pushbuffer_lock);
/* check for pushbuffer wrapping */
- if (nvavp->pushbuf_index >= nvavp->pushbuf_fence)
- nvavp->pushbuf_index = 0;
+ if (channel_info->pushbuf_index >= channel_info->pushbuf_fence)
+ channel_info->pushbuf_index = 0;
if (!ext_ucode_flag) {
setucode_cmd =
NVE26E_CH_OPCODE_INCR(NVE276_SET_MICROCODE_A, 3);
- index = wordcount + nvavp->pushbuf_index;
- writel(setucode_cmd, (nvavp->pushbuf_data + index));
+ index = wordcount + channel_info->pushbuf_index;
+ writel(setucode_cmd, (channel_info->pushbuf_data + index));
wordcount += sizeof(u32);
- index = wordcount + nvavp->pushbuf_index;
- writel(0, (nvavp->pushbuf_data + index));
+ index = wordcount + channel_info->pushbuf_index;
+ writel(0, (channel_info->pushbuf_data + index));
wordcount += sizeof(u32);
- index = wordcount + nvavp->pushbuf_index;
- writel(nvavp->ucode_info.phys, (nvavp->pushbuf_data + index));
+ index = wordcount + channel_info->pushbuf_index;
+ writel(nvavp->ucode_info.phys,
+ (channel_info->pushbuf_data + index));
wordcount += sizeof(u32);
- index = wordcount + nvavp->pushbuf_index;
- writel(nvavp->ucode_info.size, (nvavp->pushbuf_data + index));
+ index = wordcount + channel_info->pushbuf_index;
+ writel(nvavp->ucode_info.size,
+ (channel_info->pushbuf_data + index));
wordcount += sizeof(u32);
}
@@ -474,39 +582,58 @@ static int nvavp_pushbuffer_update(struct nvavp_info *nvavp, u32 phys_addr,
}
/* write commands out */
- index = wordcount + nvavp->pushbuf_index;
- writel(gather_cmd, (nvavp->pushbuf_data + index));
+ index = wordcount + channel_info->pushbuf_index;
+ writel(gather_cmd, (channel_info->pushbuf_data + index));
wordcount += sizeof(u32);
- index = wordcount + nvavp->pushbuf_index;
- writel(phys_addr, (nvavp->pushbuf_data + index));
+ index = wordcount + channel_info->pushbuf_index;
+ writel(phys_addr, (channel_info->pushbuf_data + index));
wordcount += sizeof(u32);
if (syncpt) {
- index = wordcount + nvavp->pushbuf_index;
- writel(sync, (nvavp->pushbuf_data + index));
+ index = wordcount + channel_info->pushbuf_index;
+ writel(sync, (channel_info->pushbuf_data + index));
wordcount += sizeof(u32);
}
/* enable clocks to VDE/BSEV */
- nvavp_clk_ctrl(nvavp, 1);
+ if (IS_VIDEO_CHANNEL_ID(channel_id)) {
+ mutex_lock(&nvavp->open_lock);
+ if (!nvavp->pending) {
+ nvavp_clks_enable(nvavp);
+ nvavp->pending = true;
+ }
+ mutex_unlock(&nvavp->open_lock);
+ }
/* update put pointer */
- nvavp->pushbuf_index = (nvavp->pushbuf_index + wordcount) &
+ channel_info->pushbuf_index = (channel_info->pushbuf_index + wordcount)&
(NVAVP_PUSHBUFFER_SIZE - 1);
- writel(nvavp->pushbuf_index, &control->put);
+
+ writel(channel_info->pushbuf_index, &control->put);
wmb();
/* wake up avp */
- writel(0xA0000001, NVAVP_OS_OUTBOX);
+ if (IS_VIDEO_CHANNEL_ID(channel_id)) {
+ pr_debug("Wake up Video Channel\n");
+ writel(0xA0000001, NVAVP_OS_OUTBOX);
+ }
+ else {
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ if (IS_AUDIO_CHANNEL_ID(channel_id)) {
+ pr_debug("Wake up Audio Channel\n");
+ writel(0xA0000002, NVAVP_OS_OUTBOX);
+ }
+#endif
+ }
/* Fill out fence struct */
if (syncpt) {
syncpt->id = nvavp->syncpt_id;
syncpt->value = value;
}
- mutex_unlock(&nvavp->pushbuffer_lock);
+ mutex_unlock(&channel_info->pushbuffer_lock);
return 0;
}
@@ -531,14 +658,14 @@ static int nvavp_load_ucode(struct nvavp_info *nvavp)
sprintf(fw_ucode_file, "nvavp_vid_ucode.bin");
ret = request_firmware(&nvavp_ucode_fw, fw_ucode_file,
- nvavp->misc_dev.this_device);
+ nvavp->video_misc_dev.this_device);
if (ret) {
/* Try alternative version */
sprintf(fw_ucode_file, "nvavp_vid_ucode_alt.bin");
ret = request_firmware(&nvavp_ucode_fw,
fw_ucode_file,
- nvavp->misc_dev.this_device);
+ nvavp->video_misc_dev.this_device);
if (ret) {
dev_err(&nvavp->nvhost_dev->dev,
@@ -636,7 +763,7 @@ static int nvavp_load_os(struct nvavp_info *nvavp, char *fw_os_file)
if (!os_info->os_bin) {
ret = request_firmware(&nvavp_os_fw, fw_os_file,
- nvavp->misc_dev.this_device);
+ nvavp->video_misc_dev.this_device);
if (ret) {
dev_err(&nvavp->nvhost_dev->dev,
"cannot read os firmware '%s'\n", fw_os_file);
@@ -701,14 +828,28 @@ err_req_fw:
return ret;
}
-static int nvavp_init(struct nvavp_info *nvavp)
+
+static int nvavp_os_init(struct nvavp_info *nvavp)
{
char fw_os_file[32];
int ret = 0;
+ int video_initialized, audio_initialized = 0;
+
+ video_initialized = nvavp_get_video_init_status(nvavp);
+
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ audio_initialized = nvavp_get_audio_init_status(nvavp);
+#endif
+ pr_debug("video_initialized(%d) audio_initialized(%d)\n",
+ video_initialized, audio_initialized);
- if (nvavp->initialized)
+ /* Video and Audio both are initialized */
+ if (video_initialized || audio_initialized)
return ret;
+ /* Video or Audio both are uninitialized */
+ pr_debug("video_initialized == audio_initialized (%d)\n",
+ nvavp->video_initialized);
#if defined(CONFIG_TEGRA_AVP_KERNEL_ON_MMU) /* Tegra2 with AVP MMU */
/* paddr is any address returned from nvmap_pin */
/* vaddr is AVP_KERNEL_VIRT_BASE */
@@ -752,7 +893,6 @@ static int nvavp_init(struct nvavp_info *nvavp)
nvavp->os_info.reset_addr = nvavp->os_info.phys;
nvavp->os_info.data = ioremap(nvavp->os_info.phys, SZ_1M);
#endif
-
ret = nvavp_load_os(nvavp, fw_os_file);
if (ret) {
dev_err(&nvavp->nvhost_dev->dev,
@@ -766,21 +906,45 @@ static int nvavp_init(struct nvavp_info *nvavp)
"unable to init pushbuffer\n");
goto err_exit;
}
+ tegra_init_legacy_irq_cop();
+ enable_irq(nvavp->mbox_from_avp_pend_irq);
+err_exit:
+ return ret;
+}
- ret = nvavp_load_ucode(nvavp);
+static int nvavp_init(struct nvavp_info *nvavp, int channel_id)
+{
+ int ret = 0;
+
+ ret = nvavp_os_init(nvavp);
if (ret) {
dev_err(&nvavp->nvhost_dev->dev,
- "unable to load ucode\n");
- goto err_exit;
+ "unable to load os firmware and allocate buffers\n");
}
- tegra_init_legacy_irq_cop();
+ if (IS_VIDEO_CHANNEL_ID(channel_id) &&
+ (!nvavp_get_video_init_status(nvavp)) ) {
+ pr_debug("nvavp_init : channel_ID (%d)\n", channel_id);
+ ret = nvavp_load_ucode(nvavp);
+ if (ret) {
+ dev_err(&nvavp->nvhost_dev->dev,
+ "unable to load ucode\n");
+ goto err_exit;
+ }
- nvavp_reset_vde(nvavp);
- nvavp_reset_avp(nvavp, nvavp->os_info.reset_addr);
- enable_irq(nvavp->mbox_from_avp_pend_irq);
+ nvavp_reset_vde(nvavp);
+ nvavp_reset_avp(nvavp, nvavp->os_info.reset_addr);
- nvavp->initialized = 1;
+ nvavp_set_video_init_status(nvavp, 1);
+ }
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ if (IS_AUDIO_CHANNEL_ID(channel_id) &&
+ (!nvavp_get_audio_init_status(nvavp))) {
+ pr_debug("nvavp_init : channel_ID (%d)\n", channel_id);
+ nvavp_reset_avp(nvavp, nvavp->os_info.reset_addr);
+ nvavp_set_audio_init_status(nvavp, 1);
+ }
+#endif
err_exit:
return ret;
@@ -788,22 +952,48 @@ err_exit:
static void nvavp_uninit(struct nvavp_info *nvavp)
{
- if (!nvavp->initialized)
+ int video_initialized, audio_initialized = 0;
+
+ video_initialized = nvavp_get_video_init_status(nvavp);
+
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ audio_initialized = nvavp_get_audio_init_status(nvavp);
+#endif
+
+ pr_debug("nvavp_uninit video_initialized(%d) audio_initialized(%d)\n",
+ video_initialized, audio_initialized);
+
+ /* Video and Audio both are uninitialized */
+ if (!video_initialized && !audio_initialized)
return;
- disable_irq(nvavp->mbox_from_avp_pend_irq);
+ if (video_initialized) {
+ pr_debug("nvavp_uninit nvavp->video_initialized\n");
+ cancel_work_sync(&nvavp->clock_disable_work);
- cancel_work_sync(&nvavp->clock_disable_work);
+ nvavp_halt_vde(nvavp);
- nvavp_pushbuffer_deinit(nvavp);
+ clk_disable(nvavp->sclk);
+ clk_disable(nvavp->emc_clk);
- nvavp_halt_vde(nvavp);
- nvavp_halt_avp(nvavp);
+ nvavp_set_video_init_status(nvavp, 0);
+ video_initialized = 0;
+ }
- clk_disable(nvavp->sclk);
- clk_disable(nvavp->emc_clk);
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ if (audio_initialized) {
+ nvavp_set_audio_init_status(nvavp, 0);
+ audio_initialized = 0;
+ }
+#endif
- nvavp->initialized = 0;
+ /* Video and Audio both becomes uninitialized */
+ if (video_initialized == audio_initialized) {
+ pr_debug("nvavp_uninit both channels unitialized\n");
+ disable_irq(nvavp->mbox_from_avp_pend_irq);
+ nvavp_pushbuffer_deinit(nvavp);
+ nvavp_halt_avp(nvavp);
+ }
}
static int nvavp_set_clock_ioctl(struct file *filp, unsigned int cmd,
@@ -994,7 +1184,8 @@ static int nvavp_pushbuffer_submit_ioctl(struct file *filp, unsigned int cmd,
ret = nvavp_pushbuffer_update(nvavp,
(phys_addr + hdr.cmdbuf.offset),
hdr.cmdbuf.words, &syncpt,
- (hdr.flags & NVAVP_UCODE_EXT));
+ (hdr.flags & NVAVP_UCODE_EXT),
+ clientctx->channel_id);
if (copy_to_user((void __user *)user_hdr->syncpt, &syncpt,
sizeof(struct nvavp_syncpt))) {
@@ -1005,7 +1196,8 @@ static int nvavp_pushbuffer_submit_ioctl(struct file *filp, unsigned int cmd,
ret = nvavp_pushbuffer_update(nvavp,
(phys_addr + hdr.cmdbuf.offset),
hdr.cmdbuf.words, NULL,
- (hdr.flags & NVAVP_UCODE_EXT));
+ (hdr.flags & NVAVP_UCODE_EXT),
+ clientctx->channel_id);
}
err_reloc_info:
@@ -1033,33 +1225,32 @@ static int nvavp_force_clock_stay_on_ioctl(struct file *filp, unsigned int cmd,
struct nvavp_clock_stay_on_state_args clock;
if (copy_from_user(&clock, (void __user *)arg,
- sizeof(struct nvavp_clock_stay_on_state_args)))
+ sizeof(struct nvavp_clock_stay_on_state_args)))
return -EFAULT;
dev_dbg(&nvavp->nvhost_dev->dev, "%s: state=%d\n",
__func__, clock.state);
if (clock.state != NVAVP_CLOCK_STAY_ON_DISABLED &&
- clock.state != NVAVP_CLOCK_STAY_ON_ENABLED) {
+ clock.state != NVAVP_CLOCK_STAY_ON_ENABLED) {
dev_err(&nvavp->nvhost_dev->dev, "%s: invalid argument=%d\n",
__func__, clock.state);
return -EINVAL;
}
- if (clientctx->clock_stay_on == clock.state)
- return 0;
-
- clientctx->clock_stay_on = clock.state;
-
- if (clientctx->clock_stay_on == NVAVP_CLOCK_STAY_ON_ENABLED)
- atomic_inc(&nvavp->clock_stay_on_refcount);
- else if (clientctx->clock_stay_on == NVAVP_CLOCK_STAY_ON_DISABLED)
- atomic_dec(&nvavp->clock_stay_on_refcount);
-
+ mutex_lock(&nvavp->open_lock);
+ if (clock.state) {
+ if (clientctx->clk_reqs++ == 0)
+ nvavp_clks_enable(nvavp);
+ } else {
+ if (--clientctx->clk_reqs == 0)
+ nvavp_clks_disable(nvavp);
+ }
+ mutex_unlock(&nvavp->open_lock);
return 0;
}
-static int tegra_nvavp_open(struct inode *inode, struct file *filp)
+static int tegra_nvavp_open(struct inode *inode, struct file *filp, int channel_id)
{
struct miscdevice *miscdev = filp->private_data;
struct nvavp_info *nvavp = dev_get_drvdata(miscdev->parent);
@@ -1076,15 +1267,17 @@ static int tegra_nvavp_open(struct inode *inode, struct file *filp)
mutex_lock(&nvavp->open_lock);
- if (!nvavp->refcount)
- ret = nvavp_init(nvavp);
+ pr_debug("tegra_nvavp_open channel_id (%d)\n", channel_id);
+
+ clientctx->channel_id = channel_id;
+
+ ret = nvavp_init(nvavp, channel_id);
if (!ret)
nvavp->refcount++;
clientctx->nvmap = nvavp->nvmap;
clientctx->nvavp = nvavp;
- clientctx->clock_stay_on = NVAVP_CLOCK_STAY_ON_DISABLED;
filp->private_data = clientctx;
@@ -1093,6 +1286,20 @@ static int tegra_nvavp_open(struct inode *inode, struct file *filp)
return ret;
}
+static int tegra_nvavp_video_open(struct inode *inode, struct file *filp)
+{
+ pr_debug("tegra_nvavp_video_open NVAVP_VIDEO_CHANNEL\n");
+ return tegra_nvavp_open(inode, filp, NVAVP_VIDEO_CHANNEL);
+}
+
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+static int tegra_nvavp_audio_open(struct inode *inode, struct file *filp)
+{
+ pr_debug("tegra_nvavp_audio_open NVAVP_AUDIO_CHANNEL\n");
+ return tegra_nvavp_open(inode, filp, NVAVP_AUDIO_CHANNEL);
+}
+#endif
+
static int tegra_nvavp_release(struct inode *inode, struct file *filp)
{
struct nvavp_clientctx *clientctx = filp->private_data;
@@ -1112,8 +1319,10 @@ static int tegra_nvavp_release(struct inode *inode, struct file *filp)
goto out;
}
- if (clientctx->clock_stay_on == NVAVP_CLOCK_STAY_ON_ENABLED)
- atomic_dec(&nvavp->clock_stay_on_refcount);
+ /* if this client had any requests, drop our clk ref */
+ if (clientctx->clk_reqs)
+ nvavp_clks_disable(nvavp);
+
if (nvavp->refcount > 0)
nvavp->refcount--;
if (!nvavp->refcount)
@@ -1165,20 +1374,30 @@ static long tegra_nvavp_ioctl(struct file *filp, unsigned int cmd,
return ret;
}
-static const struct file_operations tegra_nvavp_fops = {
+static const struct file_operations tegra_video_nvavp_fops = {
.owner = THIS_MODULE,
- .open = tegra_nvavp_open,
+ .open = tegra_nvavp_video_open,
.release = tegra_nvavp_release,
.unlocked_ioctl = tegra_nvavp_ioctl,
};
-static int tegra_nvavp_probe(struct nvhost_device *ndev)
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+static const struct file_operations tegra_audio_nvavp_fops = {
+ .owner = THIS_MODULE,
+ .open = tegra_nvavp_audio_open,
+ .release = tegra_nvavp_release,
+ .unlocked_ioctl = tegra_nvavp_ioctl,
+};
+#endif
+
+static int tegra_nvavp_probe(struct nvhost_device *ndev,
+ struct nvhost_device_id *id_table)
{
struct nvavp_info *nvavp;
int irq;
unsigned int heap_mask;
u32 iovmm_addr;
- int ret = 0;
+ int ret = 0, channel_id;
irq = nvhost_get_irq_byname(ndev, "mbox_from_nvavp_pending");
if (irq < 0) {
@@ -1186,7 +1405,6 @@ static int tegra_nvavp_probe(struct nvhost_device *ndev)
return -EINVAL;
}
-
nvavp = kzalloc(sizeof(struct nvavp_info), GFP_KERNEL);
if (!nvavp) {
dev_err(&ndev->dev, "cannot allocate avp_info\n");
@@ -1195,13 +1413,6 @@ static int tegra_nvavp_probe(struct nvhost_device *ndev)
memset(nvavp, 0, sizeof(*nvavp));
- nvavp->nvhost_syncpt = &nvhost_get_host(ndev)->syncpt;
- if (!nvavp->nvhost_syncpt) {
- dev_err(&ndev->dev, "cannot get syncpt handle\n");
- ret = -ENOENT;
- goto err_get_syncpt;
- }
-
nvavp->nvmap = nvmap_create_client(nvmap_dev, "nvavp_drv");
if (IS_ERR_OR_NULL(nvavp->nvmap)) {
dev_err(&ndev->dev, "cannot create nvmap client\n");
@@ -1289,7 +1500,9 @@ static int tegra_nvavp_probe(struct nvhost_device *ndev)
nvavp->mbox_from_avp_pend_irq = irq;
mutex_init(&nvavp->open_lock);
- mutex_init(&nvavp->pushbuffer_lock);
+
+ for (channel_id = 0; channel_id < NVAVP_NUM_CHANNELS; channel_id++)
+ mutex_init(&nvavp->channel_info[channel_id].pushbuffer_lock);
/* TODO DO NOT USE NVAVP DEVICE */
nvavp->cop_clk = clk_get(&ndev->dev, "cop");
@@ -1332,18 +1545,32 @@ static int tegra_nvavp_probe(struct nvhost_device *ndev)
INIT_WORK(&nvavp->clock_disable_work, clock_disable_handler);
- nvavp->misc_dev.minor = MISC_DYNAMIC_MINOR;
- nvavp->misc_dev.name = "tegra_avpchannel";
- nvavp->misc_dev.fops = &tegra_nvavp_fops;
- nvavp->misc_dev.mode = S_IRWXUGO;
- nvavp->misc_dev.parent = &ndev->dev;
+ nvavp->video_misc_dev.minor = MISC_DYNAMIC_MINOR;
+ nvavp->video_misc_dev.name = "tegra_avpchannel";
+ nvavp->video_misc_dev.fops = &tegra_video_nvavp_fops;
+ nvavp->video_misc_dev.mode = S_IRWXUGO;
+ nvavp->video_misc_dev.parent = &ndev->dev;
- ret = misc_register(&nvavp->misc_dev);
+ ret = misc_register(&nvavp->video_misc_dev);
if (ret) {
dev_err(&ndev->dev, "unable to register misc device!\n");
goto err_misc_reg;
}
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ nvavp->audio_misc_dev.minor = MISC_DYNAMIC_MINOR;
+ nvavp->audio_misc_dev.name = "tegra_audio_avpchannel";
+ nvavp->audio_misc_dev.fops = &tegra_audio_nvavp_fops;
+ nvavp->audio_misc_dev.mode = S_IRWXUGO;
+ nvavp->audio_misc_dev.parent = &ndev->dev;
+
+ ret = misc_register(&nvavp->audio_misc_dev);
+ if (ret) {
+ dev_err(&ndev->dev, "unable to register misc device!\n");
+ goto err_audio_misc_reg;
+ }
+#endif
+
ret = request_irq(irq, nvavp_mbox_pending_isr, 0,
TEGRA_NVAVP_NAME, nvavp);
if (ret) {
@@ -1358,7 +1585,11 @@ static int tegra_nvavp_probe(struct nvhost_device *ndev)
return 0;
err_req_irq_pend:
- misc_deregister(&nvavp->misc_dev);
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ misc_deregister(&nvavp->audio_misc_dev);
+err_audio_misc_reg:
+#endif
+ misc_deregister(&nvavp->video_misc_dev);
err_misc_reg:
clk_put(nvavp->emc_clk);
err_get_emc_clk:
@@ -1404,8 +1635,11 @@ static int tegra_nvavp_remove(struct nvhost_device *ndev)
nvavp_unload_ucode(nvavp);
nvavp_unload_os(nvavp);
- misc_deregister(&nvavp->misc_dev);
+ misc_deregister(&nvavp->video_misc_dev);
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ misc_deregister(&nvavp->audio_misc_dev);
+#endif
clk_put(nvavp->bsev_clk);
clk_put(nvavp->vde_clk);
clk_put(nvavp->cop_clk);
@@ -1428,7 +1662,7 @@ static int tegra_nvavp_suspend(struct nvhost_device *ndev, pm_message_t state)
mutex_lock(&nvavp->open_lock);
if (nvavp->refcount) {
- if (nvavp_check_idle(nvavp))
+ if (!nvavp->clk_enabled)
nvavp_uninit(nvavp);
else
ret = -EBUSY;
@@ -1446,7 +1680,7 @@ static int tegra_nvavp_resume(struct nvhost_device *ndev)
mutex_lock(&nvavp->open_lock);
if (nvavp->refcount)
- nvavp_init(nvavp);
+ nvavp_init(nvavp, NVAVP_VIDEO_CHANNEL);
mutex_unlock(&nvavp->open_lock);
diff --git a/drivers/media/video/tegra/ov2710.c b/drivers/media/video/tegra/ov2710.c
index 5e8eaa123124..293cb8932dfb 100644
--- a/drivers/media/video/tegra/ov2710.c
+++ b/drivers/media/video/tegra/ov2710.c
@@ -21,6 +21,8 @@
#include <linux/uaccess.h>
#include <media/ov2710.h>
+#define SIZEOF_I2C_TRANSBUF 32
+
struct ov2710_reg {
u16 addr;
u16 val;
@@ -30,6 +32,7 @@ struct ov2710_info {
int mode;
struct i2c_client *i2c_client;
struct ov2710_platform_data *pdata;
+ u8 i2c_trans_buf[SIZEOF_I2C_TRANSBUF];
};
#define OV2710_TABLE_WAIT_MS 0
@@ -152,7 +155,7 @@ static struct ov2710_reg mode_1920x1080[] = {
{0x3704, 0x44},
{0x3801, 0xd2},
- {0x3503, 0x17},
+ {0x3503, 0x33},
{0x3500, 0x00},
{0x3501, 0x00},
{0x3502, 0x00},
@@ -283,7 +286,7 @@ static struct ov2710_reg mode_1280x720[] = {
{0x3704, 0x40},
{0x3801, 0xbc},
- {0x3503, 0x17},
+ {0x3503, 0x33},
{0x3500, 0x00},
{0x3501, 0x00},
{0x3502, 0x00},
@@ -400,14 +403,39 @@ static int ov2710_write_reg(struct i2c_client *client, u16 addr, u8 val)
return err;
}
-static int ov2710_write_table(struct i2c_client *client,
+static int ov2710_write_bulk_reg(struct i2c_client *client, u8 *data, int len)
+{
+ int err;
+ struct i2c_msg msg;
+
+ if (!client->adapter)
+ return -ENODEV;
+
+ msg.addr = client->addr;
+ msg.flags = 0;
+ msg.len = len;
+ msg.buf = data;
+
+ err = i2c_transfer(client->adapter, &msg, 1);
+ if (err == 1)
+ return 0;
+
+ pr_err("ov2710: i2c bulk transfer failed at %x\n",
+ (int)data[0] << 8 | data[1]);
+
+ return err;
+}
+
+static int ov2710_write_table(struct ov2710_info *info,
const struct ov2710_reg table[],
const struct ov2710_reg override_list[],
int num_override_regs)
{
int err;
- const struct ov2710_reg *next;
- int i;
+ const struct ov2710_reg *next, *n_next;
+ u8 *b_ptr = info->i2c_trans_buf;
+ unsigned int buf_filled = 0;
+ unsigned int i;
u16 val;
for (next = table; next->addr != OV2710_TABLE_END; next++) {
@@ -416,9 +444,7 @@ static int ov2710_write_table(struct i2c_client *client,
continue;
}
-
val = next->val;
-
/* When an override list is passed in, replace the reg */
/* value to write if the reg is in the list */
if (override_list) {
@@ -430,9 +456,28 @@ static int ov2710_write_table(struct i2c_client *client,
}
}
- err = ov2710_write_reg(client, next->addr, val);
+ if (!buf_filled) {
+ b_ptr = info->i2c_trans_buf;
+ *b_ptr++ = next->addr >> 8;
+ *b_ptr++ = next->addr & 0xff;
+ buf_filled = 2;
+ }
+ *b_ptr++ = val;
+ buf_filled++;
+
+ n_next = next + 1;
+ if (n_next->addr != OV2710_TABLE_END &&
+ n_next->addr != OV2710_TABLE_WAIT_MS &&
+ buf_filled < SIZEOF_I2C_TRANSBUF &&
+ n_next->addr == next->addr + 1) {
+ continue;
+ }
+
+ err = ov2710_write_bulk_reg(info->i2c_client,
+ info->i2c_trans_buf, buf_filled);
if (err)
return err;
+ buf_filled = 0;
}
return 0;
}
@@ -463,7 +508,7 @@ static int ov2710_set_mode(struct ov2710_info *info, struct ov2710_mode *mode)
ov2710_get_coarse_time_regs(reg_list + 2, mode->coarse_time);
ov2710_get_gain_reg(reg_list + 5, mode->gain);
- err = ov2710_write_table(info->i2c_client, mode_table[sensor_mode],
+ err = ov2710_write_table(info, mode_table[sensor_mode],
reg_list, 6);
if (err)
return err;
@@ -474,51 +519,37 @@ static int ov2710_set_mode(struct ov2710_info *info, struct ov2710_mode *mode)
static int ov2710_set_frame_length(struct ov2710_info *info, u32 frame_length)
{
- struct ov2710_reg reg_list[2];
- int i = 0;
int ret;
+ struct ov2710_reg reg_list[2];
+ u8 *b_ptr = info->i2c_trans_buf;
ov2710_get_frame_length_regs(reg_list, frame_length);
- for (i = 0; i < 2; i++) {
- ret = ov2710_write_reg(info->i2c_client, reg_list[i].addr,
- reg_list[i].val);
- if (ret)
- return ret;
- }
+ *b_ptr++ = reg_list[0].addr >> 8;
+ *b_ptr++ = reg_list[0].addr & 0xff;
+ *b_ptr++ = reg_list[0].val & 0xff;
+ *b_ptr++ = reg_list[1].val & 0xff;
+ ret = ov2710_write_bulk_reg(info->i2c_client, info->i2c_trans_buf, 4);
- return 0;
+ return ret;
}
static int ov2710_set_coarse_time(struct ov2710_info *info, u32 coarse_time)
{
int ret;
-
struct ov2710_reg reg_list[3];
- int i = 0;
+ u8 *b_ptr = info->i2c_trans_buf;
ov2710_get_coarse_time_regs(reg_list, coarse_time);
- ret = ov2710_write_reg(info->i2c_client, 0x3212, 0x01);
- if (ret)
- return ret;
-
- for (i = 0; i < 3; i++) {
- ret = ov2710_write_reg(info->i2c_client, reg_list[i].addr,
- reg_list[i].val);
- if (ret)
- return ret;
- }
-
- ret = ov2710_write_reg(info->i2c_client, 0x3212, 0x11);
- if (ret)
- return ret;
+ *b_ptr++ = reg_list[0].addr >> 8;
+ *b_ptr++ = reg_list[0].addr & 0xff;
+ *b_ptr++ = reg_list[0].val & 0xff;
+ *b_ptr++ = reg_list[1].val & 0xff;
+ *b_ptr++ = reg_list[2].val & 0xff;
+ ret = ov2710_write_bulk_reg(info->i2c_client, info->i2c_trans_buf, 5);
- ret = ov2710_write_reg(info->i2c_client, 0x3212, 0xa1);
- if (ret)
- return ret;
-
- return 0;
+ return ret;
}
static int ov2710_set_gain(struct ov2710_info *info, u16 gain)
@@ -533,6 +564,48 @@ static int ov2710_set_gain(struct ov2710_info *info, u16 gain)
return ret;
}
+static int ov2710_set_group_hold(struct ov2710_info *info, struct ov2710_ae *ae)
+{
+ int ret;
+ int count = 0;
+ bool groupHoldEnabled = false;
+
+ if (ae->gain_enable)
+ count++;
+ if (ae->coarse_time_enable)
+ count++;
+ if (ae->frame_length_enable)
+ count++;
+ if (count >= 2)
+ groupHoldEnabled = true;
+
+ if (groupHoldEnabled) {
+ ret = ov2710_write_reg(info->i2c_client, 0x3212, 0x01);
+ if (ret)
+ return ret;
+ }
+
+ if (ae->gain_enable)
+ ov2710_set_gain(info, ae->gain);
+ if (ae->coarse_time_enable)
+ ov2710_set_coarse_time(info, ae->coarse_time);
+ if (ae->frame_length_enable)
+ ov2710_set_frame_length(info, ae->frame_length);
+
+ if (groupHoldEnabled) {
+ ret = ov2710_write_reg(info->i2c_client, 0x3212, 0x11);
+ if (ret)
+ return ret;
+
+ ret = ov2710_write_reg(info->i2c_client, 0x3212, 0xa1);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+
static int ov2710_get_status(struct ov2710_info *info, u8 *status)
{
int err;
@@ -567,6 +640,17 @@ static long ov2710_ioctl(struct file *file,
return ov2710_set_coarse_time(info, (u32)arg);
case OV2710_IOCTL_SET_GAIN:
return ov2710_set_gain(info, (u16)arg);
+ case OV2710_IOCTL_SET_GROUP_HOLD:
+ {
+ struct ov2710_ae ae;
+ if (copy_from_user(&ae,
+ (const void __user *)arg,
+ sizeof(struct ov2710_ae))) {
+ pr_info("%s %d\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+ return ov2710_set_group_hold(info, &ae);
+ }
case OV2710_IOCTL_GET_STATUS:
{
u8 status;
diff --git a/drivers/media/video/tegra/ov5640.c b/drivers/media/video/tegra/ov5640.c
new file mode 100644
index 000000000000..26580b0105e3
--- /dev/null
+++ b/drivers/media/video/tegra/ov5640.c
@@ -0,0 +1,493 @@
+/*
+ * ov5640.c - ov5640 sensor driver
+ *
+ * Copyright (c) 2011 - 2012, NVIDIA, All Rights Reserved.
+ *
+ * Contributors:
+ * Abhinav Sinha <absinha@nvidia.com>
+ *
+ * Leverage soc380.c
+ *
+ * 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.
+ */
+
+/**
+ * SetMode Sequence for 640x480. Phase 0. Sensor Dependent.
+ * This sequence should put sensor in streaming mode for 640x480
+ * This is usually given by the FAE or the sensor vendor.
+ */
+
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/i2c.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <media/ov5640.h>
+
+#include "ov5640_tables.h"
+
+/* Focuser single step & full scale transition time truth table
+ * in the format of:
+ * index mode single step transition full scale transition
+ * 0 0 0 0
+ * 1 1 50uS 51.2mS
+ * 2 1 100uS 102.3mS
+ * 3 1 200uS 204.6mS
+ * 4 1 400uS 409.2mS
+ * 5 1 800uS 818.4mS
+ * 6 1 1600uS 1637.0mS
+ * 7 1 3200uS 3274.0mS
+ * 8 0 0 0
+ * 9 2 50uS 1.1mS
+ * A 2 100uS 2.2mS
+ * B 2 200uS 4.4mS
+ * C 2 400uS 8.8mS
+ * D 2 800uS 17.6mS
+ * E 2 1600uS 35.2mS
+ * F 2 3200uS 70.4mS
+ */
+
+/* pick up the mode index setting and its settle time from the above table */
+#define OV5640_VCM_DACMODE 0x3602
+#define OV5640_TRANSITION_MODE 0x0B
+#define SETTLETIME_MS 5
+
+#define POS_LOW (0)
+#define POS_HIGH (1023)
+#define FPOS_COUNT 1024
+#define FOCAL_LENGTH (10.0f)
+#define FNUMBER (2.8f)
+
+#define SIZEOF_I2C_TRANSBUF 64
+
+struct ov5640_info {
+ int mode;
+ struct miscdevice miscdev_info;
+ struct i2c_client *i2c_client;
+ struct ov5640_platform_data *pdata;
+ struct ov5640_config focuser;
+ int af_fw_loaded;
+ struct kobject *kobj;
+ struct device *dev;
+ u8 i2c_trans_buf[SIZEOF_I2C_TRANSBUF];
+};
+
+static int ov5640_read_reg(struct i2c_client *client, u16 addr, u8 *val)
+{
+ int err;
+ struct i2c_msg msg[2];
+ unsigned char data[3];
+
+ if (!client->adapter)
+ return -ENODEV;
+
+ msg[0].addr = client->addr;
+ msg[0].flags = 0;
+ msg[0].len = 2;
+ msg[0].buf = data;
+
+ /* high byte goes out first */
+ data[0] = (u8) (addr >> 8);
+ data[1] = (u8) (addr & 0xff);
+
+ msg[1].addr = client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = 1;
+ msg[1].buf = data + 2;
+
+ err = i2c_transfer(client->adapter, msg, 2);
+
+ if (err != 2)
+ return -EINVAL;
+
+ *val = data[2];
+
+ return 0;
+}
+
+#ifdef KERNEL_WARNING
+static int ov5640_write_reg(struct i2c_client *client, u8 addr, u8 value)
+{
+ int count;
+ struct i2c_msg msg[1];
+ unsigned char data[4];
+
+ if (!client->adapter)
+ return -ENODEV;
+
+ data[0] = addr;
+ data[1] = (u8) (addr & 0xff);
+ data[2] = value;
+
+ msg[0].addr = client->addr;
+ msg[0].flags = 0;
+ msg[0].len = 3;
+ msg[0].buf = data;
+
+ count = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
+ if (count == ARRAY_SIZE(msg))
+ return 0;
+ dev_err(&client->dev,
+ "ov5840: i2c transfer failed, addr: %x, value: %02x\n",
+ addr, (u32)value);
+ return -EIO;
+}
+#endif
+
+static int ov5640_write_bulk_reg(struct i2c_client *client, u8 *data, int len)
+{
+ int err;
+ struct i2c_msg msg;
+
+ if (!client->adapter)
+ return -ENODEV;
+
+ msg.addr = client->addr;
+ msg.flags = 0;
+ msg.len = len;
+ msg.buf = data;
+
+ err = i2c_transfer(client->adapter, &msg, 1);
+ if (err == 1)
+ return 0;
+
+ dev_err(&client->dev, "ov5640: i2c transfer failed at %x\n",
+ (int)data[0] << 8 | data[1]);
+
+ return err;
+}
+
+static int ov5640_write_table(struct ov5640_info *info,
+ struct ov5640_reg table[],
+ struct ov5640_reg override_list[],
+ int num_override_regs)
+{
+ int err;
+ struct ov5640_reg *next, *n_next;
+ u8 *b_ptr = info->i2c_trans_buf;
+ unsigned int buf_filled = 0;
+ int i;
+ u16 val;
+
+ for (next = table; next->addr != OV5640_TABLE_END; next++) {
+ if (next->addr == OV5640_TABLE_WAIT_MS) {
+ msleep(next->val);
+ continue;
+ }
+
+ val = next->val;
+
+ /* When an override list is passed in, replace the reg */
+ /* value to write if the reg is in the list */
+ if (override_list) {
+ for (i = 0; i < num_override_regs; i++) {
+ if (next->addr == override_list[i].addr) {
+ val = override_list[i].val;
+ break;
+ }
+ }
+ }
+
+ if (!buf_filled) {
+ b_ptr = info->i2c_trans_buf;
+ *b_ptr++ = next->addr >> 8;
+ *b_ptr++ = next->addr & 0xff;
+ buf_filled = 2;
+ }
+ *b_ptr++ = val;
+ buf_filled++;
+
+ n_next = next + 1;
+ if (n_next->addr != OV5640_TABLE_END &&
+ n_next->addr != OV5640_TABLE_WAIT_MS &&
+ buf_filled < SIZEOF_I2C_TRANSBUF &&
+ n_next->addr == next->addr + 1) {
+ continue;
+ }
+
+ err = ov5640_write_bulk_reg(info->i2c_client,
+ info->i2c_trans_buf, buf_filled);
+ if (err)
+ return err;
+
+ buf_filled = 0;
+ }
+ return 0;
+}
+
+static int ov5640_set_mode(struct ov5640_info *info, struct ov5640_mode *mode)
+{
+ int sensor_mode;
+ int err;
+
+ dev_info(info->dev, "%s: xres %u yres %u\n",
+ __func__, mode->xres, mode->yres);
+ if (!info->af_fw_loaded) {
+ err = ov5640_write_table(info, tbl_af_firmware, NULL, 0);
+ if (err)
+ return err;
+ info->af_fw_loaded = 1;
+ }
+
+ if (mode->xres == 2592 && mode->yres == 1944)
+ sensor_mode = OV5640_MODE_2592x1944;
+ else if (mode->xres == 1920 && mode->yres == 1080)
+ sensor_mode = OV5640_MODE_1920x1080;
+ else if (mode->xres == 1296 && mode->yres == 964)
+ sensor_mode = OV5640_MODE_1296x972;
+ else {
+ dev_info(info->dev, "%s: invalid resolution: %d %d\n",
+ __func__, mode->xres, mode->yres);
+ return -EINVAL;
+ }
+
+ err = ov5640_write_table(info, mode_table[sensor_mode],
+ NULL, 0);
+ if (err)
+ return err;
+
+ info->mode = sensor_mode;
+ return 0;
+}
+
+static int ov5640_set_af_mode(struct ov5640_info *info, u8 mode)
+{
+ dev_info(info->dev, "%s: mode %d\n", __func__, mode);
+ if (mode == OV5640_AF_INIFINITY)
+ return ov5640_write_table(info, tbl_release_focus, NULL, 0);
+
+ if (mode == OV5640_AF_TRIGGER)
+ return ov5640_write_table(info, tbl_single_focus, NULL, 0);
+
+ return -EINVAL;
+}
+
+static int ov5640_get_af_status(struct ov5640_info *info, u8 *val)
+{
+ int err;
+
+ err = ov5640_read_reg(info->i2c_client, 0x3023, val);
+ if (err)
+ return -EINVAL;
+
+ dev_info(info->dev, "%s: value %02x\n", __func__, (u32)val);
+ return 0;
+}
+
+static int ov5640_set_position(struct ov5640_info *info, u32 position)
+{
+ u8 data[4];
+
+ if (position < info->focuser.pos_low ||
+ position > info->focuser.pos_high)
+ return -EINVAL;
+
+ data[0] = (OV5640_VCM_DACMODE >> 8) & 0xff;
+ data[1] = OV5640_VCM_DACMODE & 0xff;
+ data[2] = ((position & 0xf) << 4) | OV5640_TRANSITION_MODE;
+ data[3] = (position * 0x3f0) >> 4;
+ return ov5640_write_bulk_reg(info->i2c_client, data, 4);
+}
+
+static int ov5640_set_power(struct ov5640_info *info, u32 level)
+{
+ switch (level) {
+ case OV5640_POWER_LEVEL_OFF:
+ case OV5640_POWER_LEVEL_SUS:
+ if (info->pdata && info->pdata->power_off)
+ info->pdata->power_off();
+ info->af_fw_loaded = 0;
+ info->mode = 0;
+ break;
+ case OV5640_POWER_LEVEL_ON:
+ if (info->pdata && info->pdata->power_on)
+ info->pdata->power_on();
+ break;
+ default:
+ dev_err(info->dev, "unknown power level %d.\n", level);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static long ov5640_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct ov5640_info *info = file->private_data;
+
+ switch (cmd) {
+ case OV5640_IOCTL_SET_SENSOR_MODE:
+ {
+ struct ov5640_mode mode;
+ if (copy_from_user(&mode,
+ (const void __user *)arg,
+ sizeof(struct ov5640_mode))) {
+ return -EFAULT;
+ }
+
+ return ov5640_set_mode(info, &mode);
+ }
+ case OV5640_IOCTL_GET_CONFIG:
+ {
+ if (copy_to_user((void __user *) arg,
+ &info->focuser,
+ sizeof(info->focuser))) {
+ dev_err(info->dev, "%s: 0x%x\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ break;
+ }
+ case OV5640_IOCTL_GET_AF_STATUS:
+ {
+ int err;
+ u8 val;
+
+ if (!info->af_fw_loaded) {
+ dev_err(info->dev, "OV5640 AF fw not loaded!\n");
+ break;
+ }
+
+ err = ov5640_get_af_status(info, &val);
+ if (err)
+ return err;
+
+ if (copy_to_user((void __user *) arg,
+ &val, sizeof(val))) {
+ dev_err(info->dev, "%s: 0x%x\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+ break;
+ }
+ case OV5640_IOCTL_SET_AF_MODE:
+ if (!info->af_fw_loaded) {
+ dev_err(info->dev, "OV5640 AF fw not loaded!\n");
+ break;
+ }
+ return ov5640_set_af_mode(info, (u8)arg);
+ case OV5640_IOCTL_POWER_LEVEL:
+ return ov5640_set_power(info, (u32)arg);
+ case OV5640_IOCTL_SET_FPOSITION:
+ return ov5640_set_position(info, (u32)arg);
+ case OV5640_IOCTL_GET_SENSOR_STATUS:
+ {
+ u8 status = 0;
+ if (copy_to_user((void __user *)arg, &status,
+ 1)) {
+ dev_info(info->dev, "%s %d\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+ return 0;
+ }
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int ov5640_open(struct inode *inode, struct file *file)
+{
+ struct miscdevice *miscdev = file->private_data;
+ struct ov5640_info *info;
+
+ pr_info("%s\n", __func__);
+ if (!miscdev) {
+ pr_err("miscdev == NULL\n");
+ return -1;
+ }
+ info = container_of(miscdev, struct ov5640_info, miscdev_info);
+ file->private_data = info;
+
+ return 0;
+}
+
+int ov5640_release(struct inode *inode, struct file *file)
+{
+ file->private_data = NULL;
+ pr_info("%s\n", __func__);
+ return 0;
+}
+
+static const struct file_operations ov5640_fileops = {
+ .owner = THIS_MODULE,
+ .open = ov5640_open,
+ .unlocked_ioctl = ov5640_ioctl,
+ .release = ov5640_release,
+};
+
+static struct miscdevice ov5640_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "ov5640",
+ .fops = &ov5640_fileops,
+};
+
+static int ov5640_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct ov5640_info *info;
+ int err;
+
+ dev_info(&client->dev, "ov5640: probing sensor.\n");
+
+ info = devm_kzalloc(&client->dev,
+ sizeof(struct ov5640_info), GFP_KERNEL);
+ if (!info) {
+ dev_err(&client->dev, "ov5640: Unable to allocate memory!\n");
+ return -ENOMEM;
+ }
+
+ memcpy(&(info->miscdev_info),
+ &ov5640_device,
+ sizeof(struct miscdevice));
+
+ err = misc_register(&(info->miscdev_info));
+ if (err) {
+ dev_err(&client->dev,
+ "ov5640: Unable to register misc device!\n");
+ devm_kfree(&client->dev, info);
+ return err;
+ }
+
+ info->dev = &client->dev;
+ info->pdata = client->dev.platform_data;
+ info->i2c_client = client;
+ info->focuser.settle_time = SETTLETIME_MS;
+ info->focuser.focal_length = FOCAL_LENGTH;
+ info->focuser.fnumber = FNUMBER;
+ info->focuser.pos_low = POS_LOW;
+ info->focuser.pos_high = POS_HIGH;
+
+ i2c_set_clientdata(client, info);
+ return 0;
+}
+
+static int ov5640_remove(struct i2c_client *client)
+{
+ struct ov5640_info *info;
+ info = i2c_get_clientdata(client);
+ misc_deregister(&ov5640_device);
+ return 0;
+}
+
+static const struct i2c_device_id ov5640_id[] = {
+ { "ov5640", 0 },
+ { },
+};
+
+MODULE_DEVICE_TABLE(i2c, ov5640_id);
+
+static struct i2c_driver ov5640_i2c_driver = {
+ .driver = {
+ .name = "ov5640",
+ .owner = THIS_MODULE,
+ },
+ .probe = ov5640_probe,
+ .remove = ov5640_remove,
+ .id_table = ov5640_id,
+};
+
+module_i2c_driver(ov5640_i2c_driver);
diff --git a/drivers/media/video/tegra/ov5640_tables.h b/drivers/media/video/tegra/ov5640_tables.h
new file mode 100644
index 000000000000..94cf1da31ec2
--- /dev/null
+++ b/drivers/media/video/tegra/ov5640_tables.h
@@ -0,0 +1,4582 @@
+/*
+ * ov5640_tables.h - table header for YUV camera sensor OV5640 driver.
+ *
+ * Copyright (C) 2012 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU 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 OV5640_I2C_TABLES
+#define OV5640_I2C_TABLES
+
+struct ov5640_reg {
+ u16 addr;
+ u16 val;
+};
+
+#define OV5640_TABLE_WAIT_MS 0
+#define OV5640_TABLE_END 1
+
+static struct ov5640_reg mode_2592x1944[] = {
+ /* PLL Control MIPI bit rate/lane = 672MHz, 16-bit mode.
+ * Output size: 2608x1948 (0, 0) - (2623, 1951),
+ * Line Length = 2844, Frame Length = 1968
+ */
+ {0x3103, 0x11},
+ {0x3008, 0x82},
+ {OV5640_TABLE_WAIT_MS, 5},
+ {0x3008, 0x42},
+ {0x3103, 0x03},
+ {0x3017, 0x00},
+ {0x3018, 0x00},
+ {0x3034, 0x18},
+ {0x3035, 0x11},
+ {0x3036, 0x54},
+ {0x3037, 0x13},
+ {0x3108, 0x01},
+ {0x3630, 0x36},
+ {0x3631, 0x0e},
+ {0x3632, 0xe2},
+ {0x3633, 0x12},
+ {0x3621, 0xe0},
+ {0x3704, 0xa0},
+ {0x3703, 0x5a},
+ {0x3715, 0x78},
+ {0x3717, 0x01},
+ {0x370b, 0x60},
+ {0x3705, 0x1a},
+ {0x3905, 0x02},
+ {0x3906, 0x10},
+ {0x3901, 0x0a},
+ {0x3731, 0x12},
+ {0x3600, 0x08},
+ {0x3601, 0x33},
+ {0x302d, 0x60},
+ {0x3620, 0x52},
+ {0x371b, 0x20},
+ {0x471c, 0x50},
+ {0x3a13, 0x43},
+ {0x3a18, 0x00},
+ {0x3a19, 0xf8},
+ {0x3635, 0x13},
+ {0x3636, 0x03},
+ {0x3634, 0x40},
+ {0x3622, 0x01},
+ {0x3c01, 0x34},
+ {0x3c04, 0x28},
+ {0x3c05, 0x98},
+ {0x3c06, 0x00},
+ {0x3c07, 0x07},
+ {0x3c08, 0x00},
+ {0x3c09, 0x1c},
+ {0x3c0a, 0x9c},
+ {0x3c0b, 0x40},
+ {0x3820, 0x40},
+ {0x3821, 0x06},
+ {0x3814, 0x11},
+ {0x3815, 0x11},
+ {0x3800, 0x00},
+ {0x3801, 0x00},
+ {0x3802, 0x00},
+ {0x3803, 0x00},
+ {0x3804, 0x0a},
+ {0x3805, 0x3f},
+ {0x3806, 0x07},
+ {0x3807, 0x9f},
+ {0x3808, 0x0a},
+ {0x3809, 0x30},
+ {0x380a, 0x07},
+ {0x380b, 0x9c},
+ {0x380c, 0x0b},
+ {0x380d, 0x1c},
+ {0x380e, 0x07},
+ {0x380f, 0xb0},
+ {0x3810, 0x00},
+ {0x3811, 0x08},
+ {0x3812, 0x00},
+ {0x3813, 0x02},
+ {0x3618, 0x04},
+ {0x3612, 0x2b},
+ {0x3708, 0x64},
+ {0x3709, 0x12},
+ {0x370c, 0x00},
+ {0x3a02, 0x07},
+ {0x3a03, 0xb0},
+ {0x3a08, 0x01},
+ {0x3a09, 0x27},
+ {0x3a0a, 0x00},
+ {0x3a0b, 0xf6},
+ {0x3a0e, 0x06},
+ {0x3a0d, 0x08},
+ {0x3a14, 0x07},
+ {0x3a15, 0xb0},
+ {0x4001, 0x02},
+ {0x4004, 0x06},
+ {0x3000, 0x00},
+ {0x3002, 0x1c},
+ {0x3004, 0xff},
+ {0x3006, 0xc3},
+ {0x300e, 0x45},
+ {0x302e, 0x08},
+ {0x4300, 0x32},
+ {0x4800, 0x24},
+ {0x4837, 0x0a},
+ {0x501f, 0x00},
+ {0x440e, 0x00},
+ {0x5000, 0xa7},
+ {0x5001, 0x83},
+ {0x5180, 0xff},
+ {0x5181, 0xf2},
+ {0x5182, 0x00},
+ {0x5183, 0x14},
+ {0x5184, 0x25},
+ {0x5185, 0x24},
+ {0x5186, 0x09},
+ {0x5187, 0x09},
+ {0x5188, 0x09},
+ {0x5189, 0x75},
+ {0x518a, 0x54},
+ {0x518b, 0xe0},
+ {0x518c, 0xb2},
+ {0x518d, 0x42},
+ {0x518e, 0x3d},
+ {0x518f, 0x56},
+ {0x5190, 0x46},
+ {0x5191, 0xf8},
+ {0x5192, 0x04},
+ {0x5193, 0x70},
+ {0x5194, 0xf0},
+ {0x5195, 0xf0},
+ {0x5196, 0x03},
+ {0x5197, 0x01},
+ {0x5198, 0x04},
+ {0x5199, 0x12},
+ {0x519a, 0x04},
+ {0x519b, 0x00},
+ {0x519c, 0x06},
+ {0x519d, 0x82},
+ {0x519e, 0x38},
+ {0x5381, 0x1e},
+ {0x5382, 0x5b},
+ {0x5383, 0x08},
+ {0x5384, 0x0a},
+ {0x5385, 0x7e},
+ {0x5386, 0x88},
+ {0x5387, 0x7c},
+ {0x5388, 0x6c},
+ {0x5389, 0x10},
+ {0x538a, 0x01},
+ {0x538b, 0x98},
+ {0x5300, 0x08},
+ {0x5301, 0x30},
+ {0x5302, 0x10},
+ {0x5303, 0x00},
+ {0x5304, 0x08},
+ {0x5305, 0x30},
+ {0x5306, 0x08},
+ {0x5307, 0x16},
+ {0x5309, 0x08},
+ {0x530a, 0x30},
+ {0x530b, 0x04},
+ {0x530c, 0x06},
+ {0x5480, 0x01},
+ {0x5481, 0x08},
+ {0x5482, 0x14},
+ {0x5483, 0x28},
+ {0x5484, 0x51},
+ {0x5485, 0x65},
+ {0x5486, 0x71},
+ {0x5487, 0x7d},
+ {0x5488, 0x87},
+ {0x5489, 0x91},
+ {0x548a, 0x9a},
+ {0x548b, 0xaa},
+ {0x548c, 0xb8},
+ {0x548d, 0xcd},
+ {0x548e, 0xdd},
+ {0x548f, 0xea},
+ {0x5490, 0x1d},
+ {0x5580, 0x02},
+ {0x5583, 0x40},
+ {0x5584, 0x10},
+ {0x5589, 0x10},
+ {0x558a, 0x00},
+ {0x558b, 0xf8},
+ {0x5800, 0x23},
+ {0x5801, 0x14},
+ {0x5802, 0x0f},
+ {0x5803, 0x0f},
+ {0x5804, 0x12},
+ {0x5805, 0x26},
+ {0x5806, 0x0c},
+ {0x5807, 0x08},
+ {0x5808, 0x05},
+ {0x5809, 0x05},
+ {0x580a, 0x08},
+ {0x580b, 0x0d},
+ {0x580c, 0x08},
+ {0x580d, 0x03},
+ {0x580e, 0x00},
+ {0x580f, 0x00},
+ {0x5810, 0x03},
+ {0x5811, 0x09},
+ {0x5812, 0x07},
+ {0x5813, 0x03},
+ {0x5814, 0x00},
+ {0x5815, 0x01},
+ {0x5816, 0x03},
+ {0x5817, 0x08},
+ {0x5818, 0x0d},
+ {0x5819, 0x08},
+ {0x581a, 0x05},
+ {0x581b, 0x06},
+ {0x581c, 0x08},
+ {0x581d, 0x0e},
+ {0x581e, 0x29},
+ {0x581f, 0x17},
+ {0x5820, 0x11},
+ {0x5821, 0x11},
+ {0x5822, 0x15},
+ {0x5823, 0x28},
+ {0x5824, 0x46},
+ {0x5825, 0x26},
+ {0x5826, 0x08},
+ {0x5827, 0x26},
+ {0x5828, 0x64},
+ {0x5829, 0x26},
+ {0x582a, 0x24},
+ {0x582b, 0x22},
+ {0x582c, 0x24},
+ {0x582d, 0x24},
+ {0x582e, 0x06},
+ {0x582f, 0x22},
+ {0x5830, 0x40},
+ {0x5831, 0x42},
+ {0x5832, 0x24},
+ {0x5833, 0x26},
+ {0x5834, 0x24},
+ {0x5835, 0x22},
+ {0x5836, 0x22},
+ {0x5837, 0x26},
+ {0x5838, 0x44},
+ {0x5839, 0x24},
+ {0x583a, 0x26},
+ {0x583b, 0x28},
+ {0x583c, 0x42},
+ {0x583d, 0xce},
+ {0x5025, 0x00},
+ {0x3a0f, 0x30},
+ {0x3a10, 0x28},
+ {0x3a1b, 0x30},
+ {0x3a1e, 0x26},
+ {0x3a11, 0x60},
+ {0x3a1f, 0x14},
+ {0x3008, 0x02},
+ {OV5640_TABLE_END, 0x0000}
+};
+
+static struct ov5640_reg mode_1920x1080[] = {
+ /* PLL Control MIPI bit rate/lane = 672MHz, 16-bit mode.
+ * Output size: 1936x1096 (336, 426) - (2287, 1529),
+ * Line Length = 2500, Frame Length = 1120.
+ */
+ {0x3103, 0x11},
+ {0x3008, 0x82},
+ {OV5640_TABLE_WAIT_MS, 5},
+ {0x3008, 0x42},
+ {0x3103, 0x03},
+ {0x3017, 0x00},
+ {0x3018, 0x00},
+ {0x3034, 0x18},
+ {0x3035, 0x11},
+ {0x3036, 0x54},
+ {0x3037, 0x13},
+ {0x3108, 0x01},
+ {0x3630, 0x36},
+ {0x3631, 0x0e},
+ {0x3632, 0xe2},
+ {0x3633, 0x12},
+ {0x3621, 0xe0},
+ {0x3704, 0xa0},
+ {0x3703, 0x5a},
+ {0x3715, 0x78},
+ {0x3717, 0x01},
+ {0x370b, 0x60},
+ {0x3705, 0x1a},
+ {0x3905, 0x02},
+ {0x3906, 0x10},
+ {0x3901, 0x0a},
+ {0x3731, 0x12},
+ {0x3600, 0x08},
+ {0x3601, 0x33},
+ {0x302d, 0x60},
+ {0x3620, 0x52},
+ {0x371b, 0x20},
+ {0x471c, 0x50},
+ {0x3a13, 0x43},
+ {0x3a18, 0x00},
+ {0x3a19, 0xf8},
+ {0x3635, 0x13},
+ {0x3636, 0x03},
+ {0x3634, 0x40},
+ {0x3622, 0x01},
+ {0x3c01, 0x34},
+ {0x3c04, 0x28},
+ {0x3c05, 0x98},
+ {0x3c06, 0x00},
+ {0x3c07, 0x07},
+ {0x3c08, 0x00},
+ {0x3c09, 0x1c},
+ {0x3c0a, 0x9c},
+ {0x3c0b, 0x40},
+ {0x3820, 0x40},
+ {0x3821, 0x06},
+ {0x3814, 0x11},
+ {0x3815, 0x11},
+ {0x3800, 0x01},
+ {0x3801, 0x50},
+ {0x3802, 0x01},
+ {0x3803, 0xaa},
+ {0x3804, 0x08},
+ {0x3805, 0xef},
+ {0x3806, 0x05},
+ {0x3807, 0xf9},
+ {0x3808, 0x07},
+ {0x3809, 0x90},
+ {0x380a, 0x04},
+ {0x380b, 0x48},
+ {0x380c, 0x09},
+ {0x380d, 0xc4},
+ {0x380e, 0x04},
+ {0x380f, 0x60},
+ {0x3810, 0x00},
+ {0x3811, 0x08},
+ {0x3812, 0x00},
+ {0x3813, 0x04},
+ {0x3618, 0x04},
+ {0x3612, 0x2b},
+ {0x3708, 0x64},
+ {0x3709, 0x12},
+ {0x370c, 0x00},
+ {0x3a02, 0x04},
+ {0x3a03, 0x60},
+ {0x3a08, 0x01},
+ {0x3a09, 0x50},
+ {0x3a0a, 0x01},
+ {0x3a0b, 0x18},
+ {0x3a0e, 0x03},
+ {0x3a0d, 0x04},
+ {0x3a14, 0x04},
+ {0x3a15, 0x60},
+ {0x4001, 0x02},
+ {0x4004, 0x06},
+ {0x3000, 0x00},
+ {0x3002, 0x1c},
+ {0x3004, 0xff},
+ {0x3006, 0xc3},
+ {0x300e, 0x45},
+ {0x302e, 0x08},
+ {0x4300, 0x32},
+ {0x501f, 0x00},
+ {0x4713, 0x02},
+ {0x4407, 0x04},
+ {0x440e, 0x00},
+ {0x460b, 0x37},
+ {0x460c, 0x20},
+ {0x4800, 0x24},
+ {0x4837, 0x0a},
+ {0x3824, 0x04},
+ {0x5000, 0xa7},
+ {0x5001, 0x83},
+ {0x5180, 0xff},
+ {0x5181, 0xf2},
+ {0x5182, 0x00},
+ {0x5183, 0x14},
+ {0x5184, 0x25},
+ {0x5185, 0x24},
+ {0x5186, 0x09},
+ {0x5187, 0x09},
+ {0x5188, 0x09},
+ {0x5189, 0x75},
+ {0x518a, 0x54},
+ {0x518b, 0xe0},
+ {0x518c, 0xb2},
+ {0x518d, 0x42},
+ {0x518e, 0x3d},
+ {0x518f, 0x56},
+ {0x5190, 0x46},
+ {0x5191, 0xf8},
+ {0x5192, 0x04},
+ {0x5193, 0x70},
+ {0x5194, 0xf0},
+ {0x5195, 0xf0},
+ {0x5196, 0x03},
+ {0x5197, 0x01},
+ {0x5198, 0x04},
+ {0x5199, 0x12},
+ {0x519a, 0x04},
+ {0x519b, 0x00},
+ {0x519c, 0x06},
+ {0x519d, 0x82},
+ {0x519e, 0x38},
+ {0x5381, 0x1e},
+ {0x5382, 0x5b},
+ {0x5383, 0x08},
+ {0x5384, 0x0a},
+ {0x5385, 0x7e},
+ {0x5386, 0x88},
+ {0x5387, 0x7c},
+ {0x5388, 0x6c},
+ {0x5389, 0x10},
+ {0x538a, 0x01},
+ {0x538b, 0x98},
+ {0x5300, 0x08},
+ {0x5301, 0x30},
+ {0x5302, 0x10},
+ {0x5303, 0x00},
+ {0x5304, 0x08},
+ {0x5305, 0x30},
+ {0x5306, 0x08},
+ {0x5307, 0x16},
+ {0x5309, 0x08},
+ {0x530a, 0x30},
+ {0x530b, 0x04},
+ {0x530c, 0x06},
+ {0x5480, 0x01},
+ {0x5481, 0x08},
+ {0x5482, 0x14},
+ {0x5483, 0x28},
+ {0x5484, 0x51},
+ {0x5485, 0x65},
+ {0x5486, 0x71},
+ {0x5487, 0x7d},
+
+ {0x5488, 0x87},
+ {0x5489, 0x91},
+ {0x548a, 0x9a},
+ {0x548b, 0xaa},
+ {0x548c, 0xb8},
+ {0x548d, 0xcd},
+ {0x548e, 0xdd},
+ {0x548f, 0xea},
+ {0x5490, 0x1d},
+ {0x5580, 0x02},
+ {0x5583, 0x40},
+ {0x5584, 0x10},
+ {0x5589, 0x10},
+ {0x558a, 0x00},
+ {0x558b, 0xf8},
+ {0x5800, 0x23},
+ {0x5801, 0x14},
+ {0x5802, 0x0f},
+ {0x5803, 0x0f},
+ {0x5804, 0x12},
+ {0x5805, 0x26},
+ {0x5806, 0x0c},
+ {0x5807, 0x08},
+ {0x5808, 0x05},
+ {0x5809, 0x05},
+ {0x580a, 0x08},
+ {0x580b, 0x0d},
+ {0x580c, 0x08},
+ {0x580d, 0x03},
+ {0x580e, 0x00},
+ {0x580f, 0x00},
+ {0x5810, 0x03},
+ {0x5811, 0x09},
+ {0x5812, 0x07},
+ {0x5813, 0x03},
+ {0x5814, 0x00},
+ {0x5815, 0x01},
+ {0x5816, 0x03},
+ {0x5817, 0x08},
+ {0x5818, 0x0d},
+ {0x5819, 0x08},
+ {0x581a, 0x05},
+ {0x581b, 0x06},
+ {0x581c, 0x08},
+ {0x581d, 0x0e},
+ {0x581e, 0x29},
+ {0x581f, 0x17},
+ {0x5820, 0x11},
+ {0x5821, 0x11},
+ {0x5822, 0x15},
+ {0x5823, 0x28},
+ {0x5824, 0x46},
+ {0x5825, 0x26},
+ {0x5826, 0x08},
+ {0x5827, 0x26},
+ {0x5828, 0x64},
+ {0x5829, 0x26},
+ {0x582a, 0x24},
+ {0x582b, 0x22},
+ {0x582c, 0x24},
+ {0x582d, 0x24},
+ {0x582e, 0x06},
+ {0x582f, 0x22},
+ {0x5830, 0x40},
+ {0x5831, 0x42},
+ {0x5832, 0x24},
+ {0x5833, 0x26},
+ {0x5834, 0x24},
+ {0x5835, 0x22},
+ {0x5836, 0x22},
+ {0x5837, 0x26},
+ {0x5838, 0x44},
+ {0x5839, 0x24},
+ {0x583a, 0x26},
+ {0x583b, 0x28},
+ {0x583c, 0x42},
+ {0x583d, 0xce},
+ {0x5025, 0x00},
+ {0x3a0f, 0x30},
+ {0x3a10, 0x28},
+ {0x3a1b, 0x30},
+ {0x3a1e, 0x26},
+ {0x3a11, 0x60},
+ {0x3a1f, 0x14},
+ {0x3008, 0x02},
+ {OV5640_TABLE_END, 0x0000}
+};
+
+static struct ov5640_reg mode_1296x972[] = {
+ /* PLL Control MIPI bit rate/lane = 448MHz, 16-bit mode.
+ * Output size: 1304x972 (0, 0) - (2623, 1951),
+ * Line Length = 1886, Frame Length = 990.
+ */
+ {0x3103, 0x11},
+ {0x3008, 0x82},
+ {OV5640_TABLE_WAIT_MS, 5},
+ {0x3008, 0x42},
+ {0x3103, 0x03},
+ {0x3017, 0x00},
+ {0x3018, 0x00},
+ {0x3034, 0x18},
+ {0x3035, 0x21},
+ {0x3036, 0x70},
+ {0x3037, 0x13},
+ {0x3108, 0x01},
+ {0x3630, 0x36},
+ {0x3631, 0x0e},
+ {0x3632, 0xe2},
+ {0x3633, 0x12},
+ {0x3621, 0xe0},
+ {0x3704, 0xa0},
+ {0x3703, 0x5a},
+ {0x3715, 0x78},
+ {0x3717, 0x01},
+ {0x370b, 0x60},
+ {0x3705, 0x1a},
+ {0x3905, 0x02},
+ {0x3906, 0x10},
+ {0x3901, 0x0a},
+ {0x3731, 0x12},
+ {0x3600, 0x08},
+ {0x3601, 0x33},
+ {0x302d, 0x60},
+ {0x3620, 0x52},
+ {0x371b, 0x20},
+ {0x471c, 0x50},
+ {0x3a13, 0x43},
+ {0x3a18, 0x00},
+ {0x3a19, 0xf8},
+ {0x3635, 0x13},
+ {0x3636, 0x03},
+ {0x3634, 0x40},
+ {0x3622, 0x01},
+ {0x3c01, 0x34},
+ {0x3c04, 0x28},
+ {0x3c05, 0x98},
+ {0x3c06, 0x00},
+ {0x3c07, 0x07},
+ {0x3c08, 0x00},
+ {0x3c09, 0x1c},
+ {0x3c0a, 0x9c},
+ {0x3c0b, 0x40},
+ {0x3820, 0x41},
+ {0x3821, 0x07},
+ {0x3814, 0x31},
+ {0x3815, 0x31},
+ {0x3800, 0x00},
+ {0x3801, 0x00},
+ {0x3802, 0x00},
+ {0x3803, 0x00},
+ {0x3804, 0x0a},
+ {0x3805, 0x3f},
+ {0x3806, 0x07},
+ {0x3807, 0x9f},
+ {0x3808, 0x05},
+ {0x3809, 0x18},
+ {0x380a, 0x03},
+ {0x380b, 0xcc},
+ {0x380c, 0x07},
+ {0x380d, 0x5e},
+ {0x380e, 0x03},
+ {0x380f, 0xde},
+ {0x3810, 0x00},
+ {0x3811, 0x06},
+ {0x3812, 0x00},
+ {0x3813, 0x02},
+ {0x3618, 0x00},
+ {0x3612, 0x29},
+ {0x3708, 0x62},
+ {0x3709, 0x52},
+ {0x370c, 0x03},
+ {0x3a02, 0x03},
+ {0x3a03, 0xd8},
+ {0x3a08, 0x01},
+ {0x3a09, 0x27},
+ {0x3a0a, 0x00},
+ {0x3a0b, 0xf6},
+ {0x3a0e, 0x03},
+ {0x3a0d, 0x04},
+ {0x3a14, 0x03},
+ {0x3a15, 0xd8},
+ {0x4001, 0x02},
+ {0x4004, 0x02},
+ {0x3000, 0x00},
+ {0x3002, 0x1c},
+ {0x3004, 0xff},
+ {0x3006, 0xc3},
+ {0x300e, 0x45},
+ {0x302e, 0x08},
+ {0x4300, 0x32},
+ {0x501f, 0x00},
+ {0x4713, 0x02},
+ {0x4407, 0x04},
+ {0x440e, 0x00},
+ {0x460b, 0x37},
+ {0x460c, 0x20},
+ {0x4800, 0x24},
+ {0x4837, 0x10},
+ {0x3824, 0x04},
+ {0x5000, 0xa7},
+ {0x5001, 0x83},
+ {0x5180, 0xff},
+ {0x5181, 0xf2},
+ {0x5182, 0x00},
+ {0x5183, 0x14},
+ {0x5184, 0x25},
+ {0x5185, 0x24},
+ {0x5186, 0x09},
+ {0x5187, 0x09},
+ {0x5188, 0x09},
+ {0x5189, 0x75},
+ {0x518a, 0x54},
+ {0x518b, 0xe0},
+ {0x518c, 0xb2},
+ {0x518d, 0x42},
+ {0x518e, 0x3d},
+ {0x518f, 0x56},
+ {0x5190, 0x46},
+ {0x5191, 0xf8},
+ {0x5192, 0x04},
+ {0x5193, 0x70},
+ {0x5194, 0xf0},
+ {0x5195, 0xf0},
+ {0x5196, 0x03},
+ {0x5197, 0x01},
+ {0x5198, 0x04},
+ {0x5199, 0x12},
+ {0x519a, 0x04},
+ {0x519b, 0x00},
+ {0x519c, 0x06},
+ {0x519d, 0x82},
+ {0x519e, 0x38},
+ {0x5381, 0x1e},
+ {0x5382, 0x5b},
+ {0x5383, 0x08},
+ {0x5384, 0x0a},
+ {0x5385, 0x7e},
+ {0x5386, 0x88},
+ {0x5387, 0x7c},
+ {0x5388, 0x6c},
+ {0x5389, 0x10},
+ {0x538a, 0x01},
+ {0x538b, 0x98},
+ {0x5300, 0x08},
+ {0x5301, 0x30},
+ {0x5302, 0x10},
+ {0x5303, 0x00},
+ {0x5304, 0x08},
+ {0x5305, 0x30},
+ {0x5306, 0x08},
+ {0x5307, 0x16},
+ {0x5309, 0x08},
+ {0x530a, 0x30},
+ {0x530b, 0x04},
+ {0x530c, 0x06},
+ {0x5480, 0x01},
+ {0x5481, 0x08},
+ {0x5482, 0x14},
+ {0x5483, 0x28},
+ {0x5484, 0x51},
+ {0x5485, 0x65},
+ {0x5486, 0x71},
+ {0x5487, 0x7d},
+ {0x5488, 0x87},
+ {0x5489, 0x91},
+ {0x548a, 0x9a},
+ {0x548b, 0xaa},
+ {0x548c, 0xb8},
+ {0x548d, 0xcd},
+ {0x548e, 0xdd},
+ {0x548f, 0xea},
+ {0x5490, 0x1d},
+ {0x5580, 0x02},
+ {0x5583, 0x40},
+ {0x5584, 0x10},
+ {0x5589, 0x10},
+ {0x558a, 0x00},
+ {0x558b, 0xf8},
+ {0x5800, 0x23},
+ {0x5801, 0x14},
+ {0x5802, 0x0f},
+ {0x5803, 0x0f},
+ {0x5804, 0x12},
+ {0x5805, 0x26},
+ {0x5806, 0x0c},
+ {0x5807, 0x08},
+ {0x5808, 0x05},
+ {0x5809, 0x05},
+ {0x580a, 0x08},
+ {0x580b, 0x0d},
+ {0x580c, 0x08},
+ {0x580d, 0x03},
+ {0x580e, 0x00},
+ {0x580f, 0x00},
+ {0x5810, 0x03},
+ {0x5811, 0x09},
+ {0x5812, 0x07},
+ {0x5813, 0x03},
+ {0x5814, 0x00},
+ {0x5815, 0x01},
+ {0x5816, 0x03},
+ {0x5817, 0x08},
+ {0x5818, 0x0d},
+ {0x5819, 0x08},
+ {0x581a, 0x05},
+ {0x581b, 0x06},
+ {0x581c, 0x08},
+ {0x581d, 0x0e},
+ {0x581e, 0x29},
+ {0x581f, 0x17},
+ {0x5820, 0x11},
+ {0x5821, 0x11},
+ {0x5822, 0x15},
+ {0x5823, 0x28},
+ {0x5824, 0x46},
+ {0x5825, 0x26},
+ {0x5826, 0x08},
+ {0x5827, 0x26},
+ {0x5828, 0x64},
+ {0x5829, 0x26},
+ {0x582a, 0x24},
+ {0x582b, 0x22},
+ {0x582c, 0x24},
+ {0x582d, 0x24},
+ {0x582e, 0x06},
+ {0x582f, 0x22},
+ {0x5830, 0x40},
+ {0x5831, 0x42},
+ {0x5832, 0x24},
+ {0x5833, 0x26},
+ {0x5834, 0x24},
+ {0x5835, 0x22},
+ {0x5836, 0x22},
+ {0x5837, 0x26},
+ {0x5838, 0x44},
+ {0x5839, 0x24},
+ {0x583a, 0x26},
+ {0x583b, 0x28},
+ {0x583c, 0x42},
+ {0x583d, 0xce},
+ {0x5025, 0x00},
+ {0x3a0f, 0x30},
+ {0x3a10, 0x28},
+ {0x3a1b, 0x30},
+ {0x3a1e, 0x26},
+ {0x3a11, 0x60},
+ {0x3a1f, 0x14},
+ {0x3008, 0x02},
+ {OV5640_TABLE_END, 0x0000}
+};
+
+enum {
+ OV5640_MODE_2592x1944 = 1,
+ OV5640_MODE_1920x1080,
+ OV5640_MODE_1296x972,
+};
+
+static struct ov5640_reg *mode_table[] = {
+ [OV5640_MODE_2592x1944] = mode_2592x1944,
+ [OV5640_MODE_1920x1080] = mode_1920x1080,
+ [OV5640_MODE_1296x972] = mode_1296x972,
+};
+
+static struct ov5640_reg tbl_af_firmware[] = {
+ {0x3000, 0x20},
+ {0x8000, 0x02},
+ {0x8001, 0x0b},
+ {0x8002, 0x1f},
+ {0x8003, 0x02},
+ {0x8004, 0x07},
+ {0x8005, 0x89},
+ {0x8006, 0xc2},
+ {0x8007, 0x01},
+ {0x8008, 0x22},
+ {0x8009, 0x22},
+ {0x800a, 0x00},
+ {0x800b, 0x02},
+ {0x800c, 0x0b},
+ {0x800d, 0x09},
+ {0x800e, 0xe5},
+ {0x800f, 0x40},
+ {0x8010, 0x60},
+ {0x8011, 0x03},
+ {0x8012, 0x02},
+ {0x8013, 0x00},
+ {0x8014, 0x97},
+ {0x8015, 0xf5},
+ {0x8016, 0x3f},
+ {0x8017, 0xd2},
+ {0x8018, 0x34},
+ {0x8019, 0x75},
+ {0x801a, 0x29},
+ {0x801b, 0xff},
+ {0x801c, 0x75},
+ {0x801d, 0x2a},
+ {0x801e, 0x0e},
+ {0x801f, 0x75},
+ {0x8020, 0x2b},
+ {0x8021, 0x55},
+ {0x8022, 0x75},
+ {0x8023, 0x2c},
+ {0x8024, 0x01},
+ {0x8025, 0x12},
+ {0x8026, 0x0a},
+ {0x8027, 0x0e},
+ {0x8028, 0xe4},
+ {0x8029, 0xff},
+ {0x802a, 0xef},
+ {0x802b, 0x25},
+ {0x802c, 0xe0},
+ {0x802d, 0x24},
+ {0x802e, 0x41},
+ {0x802f, 0xf8},
+ {0x8030, 0xe4},
+ {0x8031, 0xf6},
+ {0x8032, 0x08},
+ {0x8033, 0xf6},
+ {0x8034, 0x0f},
+ {0x8035, 0xbf},
+ {0x8036, 0x34},
+ {0x8037, 0xf2},
+ {0x8038, 0x90},
+ {0x8039, 0x0e},
+ {0x803a, 0x88},
+ {0x803b, 0xe4},
+ {0x803c, 0x93},
+ {0x803d, 0xff},
+ {0x803e, 0xe5},
+ {0x803f, 0x3e},
+ {0x8040, 0xc3},
+ {0x8041, 0x9f},
+ {0x8042, 0x50},
+ {0x8043, 0x04},
+ {0x8044, 0x7f},
+ {0x8045, 0x05},
+ {0x8046, 0x80},
+ {0x8047, 0x02},
+ {0x8048, 0x7f},
+ {0x8049, 0xfb},
+ {0x804a, 0x78},
+ {0x804b, 0xb0},
+ {0x804c, 0xa6},
+ {0x804d, 0x07},
+ {0x804e, 0x12},
+ {0x804f, 0x0a},
+ {0x8050, 0x78},
+ {0x8051, 0x40},
+ {0x8052, 0x04},
+ {0x8053, 0x7f},
+ {0x8054, 0x03},
+ {0x8055, 0x80},
+ {0x8056, 0x02},
+ {0x8057, 0x7f},
+ {0x8058, 0x30},
+ {0x8059, 0x78},
+ {0x805a, 0xaf},
+ {0x805b, 0xa6},
+ {0x805c, 0x07},
+ {0x805d, 0xe6},
+ {0x805e, 0x18},
+ {0x805f, 0xf6},
+ {0x8060, 0x08},
+ {0x8061, 0xe6},
+ {0x8062, 0x78},
+ {0x8063, 0xac},
+ {0x8064, 0xf6},
+ {0x8065, 0x78},
+ {0x8066, 0xaf},
+ {0x8067, 0xe6},
+ {0x8068, 0x78},
+ {0x8069, 0xad},
+ {0x806a, 0xf6},
+ {0x806b, 0x78},
+ {0x806c, 0xb2},
+ {0x806d, 0x76},
+ {0x806e, 0x33},
+ {0x806f, 0xe4},
+ {0x8070, 0x08},
+ {0x8071, 0xf6},
+ {0x8072, 0x78},
+ {0x8073, 0xab},
+ {0x8074, 0x76},
+ {0x8075, 0x01},
+ {0x8076, 0x75},
+ {0x8077, 0x3d},
+ {0x8078, 0x02},
+ {0x8079, 0x78},
+ {0x807a, 0xa9},
+ {0x807b, 0xf6},
+ {0x807c, 0x08},
+ {0x807d, 0xf6},
+ {0x807e, 0x74},
+ {0x807f, 0xff},
+ {0x8080, 0x78},
+ {0x8081, 0xb4},
+ {0x8082, 0xf6},
+ {0x8083, 0x08},
+ {0x8084, 0xf6},
+ {0x8085, 0x75},
+ {0x8086, 0x40},
+ {0x8087, 0x01},
+ {0x8088, 0x78},
+ {0x8089, 0xaf},
+ {0x808a, 0xe6},
+ {0x808b, 0x75},
+ {0x808c, 0xf0},
+ {0x808d, 0x05},
+ {0x808e, 0xa4},
+ {0x808f, 0xf5},
+ {0x8090, 0x3e},
+ {0x8091, 0x12},
+ {0x8092, 0x08},
+ {0x8093, 0x1d},
+ {0x8094, 0xc2},
+ {0x8095, 0x36},
+ {0x8096, 0x22},
+ {0x8097, 0x78},
+ {0x8098, 0xab},
+ {0x8099, 0xe6},
+ {0x809a, 0xd3},
+ {0x809b, 0x94},
+ {0x809c, 0x00},
+ {0x809d, 0x40},
+ {0x809e, 0x02},
+ {0x809f, 0x16},
+ {0x80a0, 0x22},
+ {0x80a1, 0xe5},
+ {0x80a2, 0x40},
+ {0x80a3, 0x64},
+ {0x80a4, 0x05},
+ {0x80a5, 0x70},
+ {0x80a6, 0x28},
+ {0x80a7, 0xf5},
+ {0x80a8, 0x40},
+ {0x80a9, 0xc2},
+ {0x80aa, 0x01},
+ {0x80ab, 0x78},
+ {0x80ac, 0xac},
+ {0x80ad, 0xe6},
+ {0x80ae, 0x25},
+ {0x80af, 0xe0},
+ {0x80b0, 0x24},
+ {0x80b1, 0x41},
+ {0x80b2, 0xf8},
+ {0x80b3, 0xe6},
+ {0x80b4, 0xfe},
+ {0x80b5, 0x08},
+ {0x80b6, 0xe6},
+ {0x80b7, 0xff},
+ {0x80b8, 0x78},
+ {0x80b9, 0x41},
+ {0x80ba, 0xa6},
+ {0x80bb, 0x06},
+ {0x80bc, 0x08},
+ {0x80bd, 0xa6},
+ {0x80be, 0x07},
+ {0x80bf, 0xa2},
+ {0x80c0, 0x36},
+ {0x80c1, 0xe4},
+ {0x80c2, 0x33},
+ {0x80c3, 0xf5},
+ {0x80c4, 0x31},
+ {0x80c5, 0x90},
+ {0x80c6, 0x30},
+ {0x80c7, 0x28},
+ {0x80c8, 0xf0},
+ {0x80c9, 0x75},
+ {0x80ca, 0x3f},
+ {0x80cb, 0x10},
+ {0x80cc, 0xd2},
+ {0x80cd, 0x34},
+ {0x80ce, 0x22},
+ {0x80cf, 0xe5},
+ {0x80d0, 0x3e},
+ {0x80d1, 0x75},
+ {0x80d2, 0xf0},
+ {0x80d3, 0x05},
+ {0x80d4, 0x84},
+ {0x80d5, 0x78},
+ {0x80d6, 0xaf},
+ {0x80d7, 0xf6},
+ {0x80d8, 0x90},
+ {0x80d9, 0x0e},
+ {0x80da, 0x85},
+ {0x80db, 0xe4},
+ {0x80dc, 0x93},
+ {0x80dd, 0xff},
+ {0x80de, 0x25},
+ {0x80df, 0xe0},
+ {0x80e0, 0x24},
+ {0x80e1, 0x0a},
+ {0x80e2, 0xf8},
+ {0x80e3, 0xe6},
+ {0x80e4, 0xfc},
+ {0x80e5, 0x08},
+ {0x80e6, 0xe6},
+ {0x80e7, 0xfd},
+ {0x80e8, 0x78},
+ {0x80e9, 0xaf},
+ {0x80ea, 0xe6},
+ {0x80eb, 0x25},
+ {0x80ec, 0xe0},
+ {0x80ed, 0x24},
+ {0x80ee, 0x41},
+ {0x80ef, 0xf8},
+ {0x80f0, 0xa6},
+ {0x80f1, 0x04},
+ {0x80f2, 0x08},
+ {0x80f3, 0xa6},
+ {0x80f4, 0x05},
+ {0x80f5, 0xef},
+ {0x80f6, 0x12},
+ {0x80f7, 0x0a},
+ {0x80f8, 0x7f},
+ {0x80f9, 0xd3},
+ {0x80fa, 0x78},
+ {0x80fb, 0xaa},
+ {0x80fc, 0x96},
+ {0x80fd, 0xee},
+ {0x80fe, 0x18},
+ {0x80ff, 0x96},
+ {0x8100, 0x40},
+ {0x8101, 0x0d},
+ {0x8102, 0x78},
+ {0x8103, 0xaf},
+ {0x8104, 0xe6},
+ {0x8105, 0x78},
+ {0x8106, 0xac},
+ {0x8107, 0xf6},
+ {0x8108, 0x78},
+ {0x8109, 0xa9},
+ {0x810a, 0xa6},
+ {0x810b, 0x06},
+ {0x810c, 0x08},
+ {0x810d, 0xa6},
+ {0x810e, 0x07},
+ {0x810f, 0x90},
+ {0x8110, 0x0e},
+ {0x8111, 0x85},
+ {0x8112, 0xe4},
+ {0x8113, 0x93},
+ {0x8114, 0x12},
+ {0x8115, 0x0a},
+ {0x8116, 0x7f},
+ {0x8117, 0xc3},
+ {0x8118, 0x78},
+ {0x8119, 0xb5},
+ {0x811a, 0x96},
+ {0x811b, 0xee},
+ {0x811c, 0x18},
+ {0x811d, 0x96},
+ {0x811e, 0x50},
+ {0x811f, 0x0d},
+ {0x8120, 0x78},
+ {0x8121, 0xaf},
+ {0x8122, 0xe6},
+ {0x8123, 0x78},
+ {0x8124, 0xad},
+ {0x8125, 0xf6},
+ {0x8126, 0x78},
+ {0x8127, 0xb4},
+ {0x8128, 0xa6},
+ {0x8129, 0x06},
+ {0x812a, 0x08},
+ {0x812b, 0xa6},
+ {0x812c, 0x07},
+ {0x812d, 0x78},
+ {0x812e, 0xa9},
+ {0x812f, 0xe6},
+ {0x8130, 0xfe},
+ {0x8131, 0x08},
+ {0x8132, 0xe6},
+ {0x8133, 0xc3},
+ {0x8134, 0x78},
+ {0x8135, 0xb5},
+ {0x8136, 0x96},
+ {0x8137, 0xff},
+ {0x8138, 0xee},
+ {0x8139, 0x18},
+ {0x813a, 0x96},
+ {0x813b, 0x78},
+ {0x813c, 0xb6},
+ {0x813d, 0xf6},
+ {0x813e, 0x08},
+ {0x813f, 0xa6},
+ {0x8140, 0x07},
+ {0x8141, 0x90},
+ {0x8142, 0x0e},
+ {0x8143, 0x8a},
+ {0x8144, 0xe4},
+ {0x8145, 0x18},
+ {0x8146, 0x12},
+ {0x8147, 0x0a},
+ {0x8148, 0x5d},
+ {0x8149, 0x40},
+ {0x814a, 0x02},
+ {0x814b, 0xd2},
+ {0x814c, 0x36},
+ {0x814d, 0x78},
+ {0x814e, 0xaf},
+ {0x814f, 0xe6},
+ {0x8150, 0x08},
+ {0x8151, 0x26},
+ {0x8152, 0x08},
+ {0x8153, 0xf6},
+ {0x8154, 0xe5},
+ {0x8155, 0x40},
+ {0x8156, 0x64},
+ {0x8157, 0x01},
+ {0x8158, 0x70},
+ {0x8159, 0x55},
+ {0x815a, 0xe6},
+ {0x815b, 0xc3},
+ {0x815c, 0x78},
+ {0x815d, 0xb3},
+ {0x815e, 0x12},
+ {0x815f, 0x0a},
+ {0x8160, 0x53},
+ {0x8161, 0x40},
+ {0x8162, 0x10},
+ {0x8163, 0x12},
+ {0x8164, 0x0a},
+ {0x8165, 0x4e},
+ {0x8166, 0x50},
+ {0x8167, 0x0b},
+ {0x8168, 0x30},
+ {0x8169, 0x36},
+ {0x816a, 0x41},
+ {0x816b, 0x78},
+ {0x816c, 0xaf},
+ {0x816d, 0xe6},
+ {0x816e, 0x78},
+ {0x816f, 0xac},
+ {0x8170, 0x66},
+ {0x8171, 0x60},
+ {0x8172, 0x39},
+ {0x8173, 0x12},
+ {0x8174, 0x0a},
+ {0x8175, 0x76},
+ {0x8176, 0x40},
+ {0x8177, 0x04},
+ {0x8178, 0x7f},
+ {0x8179, 0xfe},
+ {0x817a, 0x80},
+ {0x817b, 0x02},
+ {0x817c, 0x7f},
+ {0x817d, 0x02},
+ {0x817e, 0x78},
+ {0x817f, 0xb0},
+ {0x8180, 0xa6},
+ {0x8181, 0x07},
+ {0x8182, 0x78},
+ {0x8183, 0xac},
+ {0x8184, 0xe6},
+ {0x8185, 0x24},
+ {0x8186, 0x03},
+ {0x8187, 0x78},
+ {0x8188, 0xb2},
+ {0x8189, 0xf6},
+ {0x818a, 0x78},
+ {0x818b, 0xac},
+ {0x818c, 0xe6},
+ {0x818d, 0x24},
+ {0x818e, 0xfd},
+ {0x818f, 0x78},
+ {0x8190, 0xb3},
+ {0x8191, 0xf6},
+ {0x8192, 0x12},
+ {0x8193, 0x0a},
+ {0x8194, 0x76},
+ {0x8195, 0x40},
+ {0x8196, 0x06},
+ {0x8197, 0x78},
+ {0x8198, 0xb3},
+ {0x8199, 0xe6},
+ {0x819a, 0xff},
+ {0x819b, 0x80},
+ {0x819c, 0x04},
+ {0x819d, 0x78},
+ {0x819e, 0xb2},
+ {0x819f, 0xe6},
+ {0x81a0, 0xff},
+ {0x81a1, 0x78},
+ {0x81a2, 0xb1},
+ {0x81a3, 0xa6},
+ {0x81a4, 0x07},
+ {0x81a5, 0x75},
+ {0x81a6, 0x40},
+ {0x81a7, 0x02},
+ {0x81a8, 0x78},
+ {0x81a9, 0xab},
+ {0x81aa, 0x76},
+ {0x81ab, 0x01},
+ {0x81ac, 0x02},
+ {0x81ad, 0x02},
+ {0x81ae, 0x6e},
+ {0x81af, 0xe5},
+ {0x81b0, 0x40},
+ {0x81b1, 0x64},
+ {0x81b2, 0x02},
+ {0x81b3, 0x60},
+ {0x81b4, 0x03},
+ {0x81b5, 0x02},
+ {0x81b6, 0x02},
+ {0x81b7, 0x4e},
+ {0x81b8, 0x78},
+ {0x81b9, 0xb1},
+ {0x81ba, 0xe6},
+ {0x81bb, 0xff},
+ {0x81bc, 0xc3},
+ {0x81bd, 0x78},
+ {0x81be, 0xb3},
+ {0x81bf, 0x12},
+ {0x81c0, 0x0a},
+ {0x81c1, 0x54},
+ {0x81c2, 0x40},
+ {0x81c3, 0x08},
+ {0x81c4, 0x12},
+ {0x81c5, 0x0a},
+ {0x81c6, 0x4e},
+ {0x81c7, 0x50},
+ {0x81c8, 0x03},
+ {0x81c9, 0x02},
+ {0x81ca, 0x02},
+ {0x81cb, 0x4c},
+ {0x81cc, 0x12},
+ {0x81cd, 0x0a},
+ {0x81ce, 0x76},
+ {0x81cf, 0x40},
+ {0x81d0, 0x04},
+ {0x81d1, 0x7f},
+ {0x81d2, 0xff},
+ {0x81d3, 0x80},
+ {0x81d4, 0x02},
+ {0x81d5, 0x7f},
+ {0x81d6, 0x01},
+ {0x81d7, 0x78},
+ {0x81d8, 0xb0},
+ {0x81d9, 0xa6},
+ {0x81da, 0x07},
+ {0x81db, 0x78},
+ {0x81dc, 0xac},
+ {0x81dd, 0xe6},
+ {0x81de, 0x04},
+ {0x81df, 0x78},
+ {0x81e0, 0xb2},
+ {0x81e1, 0xf6},
+ {0x81e2, 0x78},
+ {0x81e3, 0xac},
+ {0x81e4, 0xe6},
+ {0x81e5, 0x14},
+ {0x81e6, 0x78},
+ {0x81e7, 0xb3},
+ {0x81e8, 0xf6},
+ {0x81e9, 0x18},
+ {0x81ea, 0x12},
+ {0x81eb, 0x0a},
+ {0x81ec, 0x78},
+ {0x81ed, 0x40},
+ {0x81ee, 0x04},
+ {0x81ef, 0xe6},
+ {0x81f0, 0xff},
+ {0x81f1, 0x80},
+ {0x81f2, 0x02},
+ {0x81f3, 0x7f},
+ {0x81f4, 0x00},
+ {0x81f5, 0x78},
+ {0x81f6, 0xb2},
+ {0x81f7, 0xa6},
+ {0x81f8, 0x07},
+ {0x81f9, 0xd3},
+ {0x81fa, 0x08},
+ {0x81fb, 0xe6},
+ {0x81fc, 0x64},
+ {0x81fd, 0x80},
+ {0x81fe, 0x94},
+ {0x81ff, 0x80},
+ {0x8200, 0x40},
+ {0x8201, 0x04},
+ {0x8202, 0xe6},
+ {0x8203, 0xff},
+ {0x8204, 0x80},
+ {0x8205, 0x02},
+ {0x8206, 0x7f},
+ {0x8207, 0x00},
+ {0x8208, 0x78},
+ {0x8209, 0xb3},
+ {0x820a, 0xa6},
+ {0x820b, 0x07},
+ {0x820c, 0xc3},
+ {0x820d, 0x18},
+ {0x820e, 0xe6},
+ {0x820f, 0x64},
+ {0x8210, 0x80},
+ {0x8211, 0x94},
+ {0x8212, 0xb3},
+ {0x8213, 0x50},
+ {0x8214, 0x04},
+ {0x8215, 0xe6},
+ {0x8216, 0xff},
+ {0x8217, 0x80},
+ {0x8218, 0x02},
+ {0x8219, 0x7f},
+ {0x821a, 0x33},
+ {0x821b, 0x78},
+ {0x821c, 0xb2},
+ {0x821d, 0xa6},
+ {0x821e, 0x07},
+ {0x821f, 0xc3},
+ {0x8220, 0x08},
+ {0x8221, 0xe6},
+ {0x8222, 0x64},
+ {0x8223, 0x80},
+ {0x8224, 0x94},
+ {0x8225, 0xb3},
+ {0x8226, 0x50},
+ {0x8227, 0x04},
+ {0x8228, 0xe6},
+ {0x8229, 0xff},
+ {0x822a, 0x80},
+ {0x822b, 0x02},
+ {0x822c, 0x7f},
+ {0x822d, 0x33},
+ {0x822e, 0x78},
+ {0x822f, 0xb3},
+ {0x8230, 0xa6},
+ {0x8231, 0x07},
+ {0x8232, 0x12},
+ {0x8233, 0x0a},
+ {0x8234, 0x76},
+ {0x8235, 0x40},
+ {0x8236, 0x06},
+ {0x8237, 0x78},
+ {0x8238, 0xb3},
+ {0x8239, 0xe6},
+ {0x823a, 0xff},
+ {0x823b, 0x80},
+ {0x823c, 0x04},
+ {0x823d, 0x78},
+ {0x823e, 0xb2},
+ {0x823f, 0xe6},
+ {0x8240, 0xff},
+ {0x8241, 0x78},
+ {0x8242, 0xb1},
+ {0x8243, 0xa6},
+ {0x8244, 0x07},
+ {0x8245, 0x75},
+ {0x8246, 0x40},
+ {0x8247, 0x03},
+ {0x8248, 0x78},
+ {0x8249, 0xab},
+ {0x824a, 0x76},
+ {0x824b, 0x01},
+ {0x824c, 0x80},
+ {0x824d, 0x20},
+ {0x824e, 0xe5},
+ {0x824f, 0x40},
+ {0x8250, 0x64},
+ {0x8251, 0x03},
+ {0x8252, 0x70},
+ {0x8253, 0x26},
+ {0x8254, 0x78},
+ {0x8255, 0xb1},
+ {0x8256, 0xe6},
+ {0x8257, 0xff},
+ {0x8258, 0xc3},
+ {0x8259, 0x78},
+ {0x825a, 0xb3},
+ {0x825b, 0x12},
+ {0x825c, 0x0a},
+ {0x825d, 0x54},
+ {0x825e, 0x40},
+ {0x825f, 0x05},
+ {0x8260, 0x12},
+ {0x8261, 0x0a},
+ {0x8262, 0x4e},
+ {0x8263, 0x40},
+ {0x8264, 0x09},
+ {0x8265, 0x78},
+ {0x8266, 0xac},
+ {0x8267, 0xe6},
+ {0x8268, 0x78},
+ {0x8269, 0xb1},
+ {0x826a, 0xf6},
+ {0x826b, 0x75},
+ {0x826c, 0x40},
+ {0x826d, 0x04},
+ {0x826e, 0x78},
+ {0x826f, 0xb1},
+ {0x8270, 0xe6},
+ {0x8271, 0x75},
+ {0x8272, 0xf0},
+ {0x8273, 0x05},
+ {0x8274, 0xa4},
+ {0x8275, 0xf5},
+ {0x8276, 0x3e},
+ {0x8277, 0x02},
+ {0x8278, 0x08},
+ {0x8279, 0x1d},
+ {0x827a, 0xe5},
+ {0x827b, 0x40},
+ {0x827c, 0xb4},
+ {0x827d, 0x04},
+ {0x827e, 0x1f},
+ {0x827f, 0x90},
+ {0x8280, 0x0e},
+ {0x8281, 0x89},
+ {0x8282, 0xe4},
+ {0x8283, 0x78},
+ {0x8284, 0xb6},
+ {0x8285, 0x12},
+ {0x8286, 0x0a},
+ {0x8287, 0x5d},
+ {0x8288, 0x40},
+ {0x8289, 0x02},
+ {0x828a, 0xd2},
+ {0x828b, 0x36},
+ {0x828c, 0x75},
+ {0x828d, 0x40},
+ {0x828e, 0x05},
+ {0x828f, 0x75},
+ {0x8290, 0x29},
+ {0x8291, 0xff},
+ {0x8292, 0x75},
+ {0x8293, 0x2a},
+ {0x8294, 0x0e},
+ {0x8295, 0x75},
+ {0x8296, 0x2b},
+ {0x8297, 0x59},
+ {0x8298, 0x75},
+ {0x8299, 0x2c},
+ {0x829a, 0x01},
+ {0x829b, 0x12},
+ {0x829c, 0x0a},
+ {0x829d, 0x0e},
+ {0x829e, 0x22},
+ {0x829f, 0xef},
+ {0x82a0, 0x8d},
+ {0x82a1, 0xf0},
+ {0x82a2, 0xa4},
+ {0x82a3, 0xa8},
+ {0x82a4, 0xf0},
+ {0x82a5, 0xcf},
+ {0x82a6, 0x8c},
+ {0x82a7, 0xf0},
+ {0x82a8, 0xa4},
+ {0x82a9, 0x28},
+ {0x82aa, 0xce},
+ {0x82ab, 0x8d},
+ {0x82ac, 0xf0},
+ {0x82ad, 0xa4},
+ {0x82ae, 0x2e},
+ {0x82af, 0xfe},
+ {0x82b0, 0x22},
+ {0x82b1, 0xbc},
+ {0x82b2, 0x00},
+ {0x82b3, 0x0b},
+ {0x82b4, 0xbe},
+ {0x82b5, 0x00},
+ {0x82b6, 0x29},
+ {0x82b7, 0xef},
+ {0x82b8, 0x8d},
+ {0x82b9, 0xf0},
+ {0x82ba, 0x84},
+ {0x82bb, 0xff},
+ {0x82bc, 0xad},
+ {0x82bd, 0xf0},
+ {0x82be, 0x22},
+ {0x82bf, 0xe4},
+ {0x82c0, 0xcc},
+ {0x82c1, 0xf8},
+ {0x82c2, 0x75},
+ {0x82c3, 0xf0},
+ {0x82c4, 0x08},
+ {0x82c5, 0xef},
+ {0x82c6, 0x2f},
+ {0x82c7, 0xff},
+ {0x82c8, 0xee},
+ {0x82c9, 0x33},
+ {0x82ca, 0xfe},
+ {0x82cb, 0xec},
+ {0x82cc, 0x33},
+ {0x82cd, 0xfc},
+ {0x82ce, 0xee},
+ {0x82cf, 0x9d},
+ {0x82d0, 0xec},
+ {0x82d1, 0x98},
+ {0x82d2, 0x40},
+ {0x82d3, 0x05},
+ {0x82d4, 0xfc},
+ {0x82d5, 0xee},
+ {0x82d6, 0x9d},
+ {0x82d7, 0xfe},
+ {0x82d8, 0x0f},
+ {0x82d9, 0xd5},
+ {0x82da, 0xf0},
+ {0x82db, 0xe9},
+ {0x82dc, 0xe4},
+ {0x82dd, 0xce},
+ {0x82de, 0xfd},
+ {0x82df, 0x22},
+ {0x82e0, 0xed},
+ {0x82e1, 0xf8},
+ {0x82e2, 0xf5},
+ {0x82e3, 0xf0},
+ {0x82e4, 0xee},
+ {0x82e5, 0x84},
+ {0x82e6, 0x20},
+ {0x82e7, 0xd2},
+ {0x82e8, 0x1c},
+ {0x82e9, 0xfe},
+ {0x82ea, 0xad},
+ {0x82eb, 0xf0},
+ {0x82ec, 0x75},
+ {0x82ed, 0xf0},
+ {0x82ee, 0x08},
+ {0x82ef, 0xef},
+ {0x82f0, 0x2f},
+ {0x82f1, 0xff},
+ {0x82f2, 0xed},
+ {0x82f3, 0x33},
+ {0x82f4, 0xfd},
+ {0x82f5, 0x40},
+ {0x82f6, 0x07},
+ {0x82f7, 0x98},
+ {0x82f8, 0x50},
+ {0x82f9, 0x06},
+ {0x82fa, 0xd5},
+ {0x82fb, 0xf0},
+ {0x82fc, 0xf2},
+ {0x82fd, 0x22},
+ {0x82fe, 0xc3},
+ {0x82ff, 0x98},
+ {0x8300, 0xfd},
+ {0x8301, 0x0f},
+ {0x8302, 0xd5},
+ {0x8303, 0xf0},
+ {0x8304, 0xea},
+ {0x8305, 0x22},
+ {0x8306, 0xe8},
+ {0x8307, 0x8f},
+ {0x8308, 0xf0},
+ {0x8309, 0xa4},
+ {0x830a, 0xcc},
+ {0x830b, 0x8b},
+ {0x830c, 0xf0},
+ {0x830d, 0xa4},
+ {0x830e, 0x2c},
+ {0x830f, 0xfc},
+ {0x8310, 0xe9},
+ {0x8311, 0x8e},
+ {0x8312, 0xf0},
+ {0x8313, 0xa4},
+ {0x8314, 0x2c},
+ {0x8315, 0xfc},
+ {0x8316, 0x8a},
+ {0x8317, 0xf0},
+ {0x8318, 0xed},
+ {0x8319, 0xa4},
+ {0x831a, 0x2c},
+ {0x831b, 0xfc},
+ {0x831c, 0xea},
+ {0x831d, 0x8e},
+ {0x831e, 0xf0},
+ {0x831f, 0xa4},
+ {0x8320, 0xcd},
+ {0x8321, 0xa8},
+ {0x8322, 0xf0},
+ {0x8323, 0x8b},
+ {0x8324, 0xf0},
+ {0x8325, 0xa4},
+ {0x8326, 0x2d},
+ {0x8327, 0xcc},
+ {0x8328, 0x38},
+ {0x8329, 0x25},
+ {0x832a, 0xf0},
+ {0x832b, 0xfd},
+ {0x832c, 0xe9},
+ {0x832d, 0x8f},
+ {0x832e, 0xf0},
+ {0x832f, 0xa4},
+ {0x8330, 0x2c},
+ {0x8331, 0xcd},
+ {0x8332, 0x35},
+ {0x8333, 0xf0},
+ {0x8334, 0xfc},
+ {0x8335, 0xeb},
+ {0x8336, 0x8e},
+ {0x8337, 0xf0},
+ {0x8338, 0xa4},
+ {0x8339, 0xfe},
+ {0x833a, 0xa9},
+ {0x833b, 0xf0},
+ {0x833c, 0xeb},
+ {0x833d, 0x8f},
+ {0x833e, 0xf0},
+ {0x833f, 0xa4},
+ {0x8340, 0xcf},
+ {0x8341, 0xc5},
+ {0x8342, 0xf0},
+ {0x8343, 0x2e},
+ {0x8344, 0xcd},
+ {0x8345, 0x39},
+ {0x8346, 0xfe},
+ {0x8347, 0xe4},
+ {0x8348, 0x3c},
+ {0x8349, 0xfc},
+ {0x834a, 0xea},
+ {0x834b, 0xa4},
+ {0x834c, 0x2d},
+ {0x834d, 0xce},
+ {0x834e, 0x35},
+ {0x834f, 0xf0},
+ {0x8350, 0xfd},
+ {0x8351, 0xe4},
+ {0x8352, 0x3c},
+ {0x8353, 0xfc},
+ {0x8354, 0x22},
+ {0x8355, 0x75},
+ {0x8356, 0xf0},
+ {0x8357, 0x08},
+ {0x8358, 0x75},
+ {0x8359, 0x82},
+ {0x835a, 0x00},
+ {0x835b, 0xef},
+ {0x835c, 0x2f},
+ {0x835d, 0xff},
+ {0x835e, 0xee},
+ {0x835f, 0x33},
+ {0x8360, 0xfe},
+ {0x8361, 0xcd},
+ {0x8362, 0x33},
+ {0x8363, 0xcd},
+ {0x8364, 0xcc},
+ {0x8365, 0x33},
+ {0x8366, 0xcc},
+ {0x8367, 0xc5},
+ {0x8368, 0x82},
+ {0x8369, 0x33},
+ {0x836a, 0xc5},
+ {0x836b, 0x82},
+ {0x836c, 0x9b},
+ {0x836d, 0xed},
+ {0x836e, 0x9a},
+ {0x836f, 0xec},
+ {0x8370, 0x99},
+ {0x8371, 0xe5},
+ {0x8372, 0x82},
+ {0x8373, 0x98},
+ {0x8374, 0x40},
+ {0x8375, 0x0c},
+ {0x8376, 0xf5},
+ {0x8377, 0x82},
+ {0x8378, 0xee},
+ {0x8379, 0x9b},
+ {0x837a, 0xfe},
+ {0x837b, 0xed},
+ {0x837c, 0x9a},
+ {0x837d, 0xfd},
+ {0x837e, 0xec},
+ {0x837f, 0x99},
+ {0x8380, 0xfc},
+ {0x8381, 0x0f},
+ {0x8382, 0xd5},
+ {0x8383, 0xf0},
+ {0x8384, 0xd6},
+ {0x8385, 0xe4},
+ {0x8386, 0xce},
+ {0x8387, 0xfb},
+ {0x8388, 0xe4},
+ {0x8389, 0xcd},
+ {0x838a, 0xfa},
+ {0x838b, 0xe4},
+ {0x838c, 0xcc},
+ {0x838d, 0xf9},
+ {0x838e, 0xa8},
+ {0x838f, 0x82},
+ {0x8390, 0x22},
+ {0x8391, 0xb8},
+ {0x8392, 0x00},
+ {0x8393, 0xc1},
+ {0x8394, 0xb9},
+ {0x8395, 0x00},
+ {0x8396, 0x59},
+ {0x8397, 0xba},
+ {0x8398, 0x00},
+ {0x8399, 0x2d},
+ {0x839a, 0xec},
+ {0x839b, 0x8b},
+ {0x839c, 0xf0},
+ {0x839d, 0x84},
+ {0x839e, 0xcf},
+ {0x839f, 0xce},
+ {0x83a0, 0xcd},
+ {0x83a1, 0xfc},
+ {0x83a2, 0xe5},
+ {0x83a3, 0xf0},
+ {0x83a4, 0xcb},
+ {0x83a5, 0xf9},
+ {0x83a6, 0x78},
+ {0x83a7, 0x18},
+ {0x83a8, 0xef},
+ {0x83a9, 0x2f},
+ {0x83aa, 0xff},
+ {0x83ab, 0xee},
+ {0x83ac, 0x33},
+ {0x83ad, 0xfe},
+ {0x83ae, 0xed},
+ {0x83af, 0x33},
+ {0x83b0, 0xfd},
+ {0x83b1, 0xec},
+ {0x83b2, 0x33},
+ {0x83b3, 0xfc},
+ {0x83b4, 0xeb},
+ {0x83b5, 0x33},
+ {0x83b6, 0xfb},
+ {0x83b7, 0x10},
+ {0x83b8, 0xd7},
+ {0x83b9, 0x03},
+ {0x83ba, 0x99},
+ {0x83bb, 0x40},
+ {0x83bc, 0x04},
+ {0x83bd, 0xeb},
+ {0x83be, 0x99},
+ {0x83bf, 0xfb},
+ {0x83c0, 0x0f},
+ {0x83c1, 0xd8},
+ {0x83c2, 0xe5},
+ {0x83c3, 0xe4},
+ {0x83c4, 0xf9},
+ {0x83c5, 0xfa},
+ {0x83c6, 0x22},
+ {0x83c7, 0x78},
+ {0x83c8, 0x18},
+ {0x83c9, 0xef},
+ {0x83ca, 0x2f},
+ {0x83cb, 0xff},
+ {0x83cc, 0xee},
+ {0x83cd, 0x33},
+ {0x83ce, 0xfe},
+ {0x83cf, 0xed},
+ {0x83d0, 0x33},
+ {0x83d1, 0xfd},
+ {0x83d2, 0xec},
+ {0x83d3, 0x33},
+ {0x83d4, 0xfc},
+ {0x83d5, 0xc9},
+ {0x83d6, 0x33},
+ {0x83d7, 0xc9},
+ {0x83d8, 0x10},
+ {0x83d9, 0xd7},
+ {0x83da, 0x05},
+ {0x83db, 0x9b},
+ {0x83dc, 0xe9},
+ {0x83dd, 0x9a},
+ {0x83de, 0x40},
+
+ {0x83df, 0x07},
+ {0x83e0, 0xec},
+ {0x83e1, 0x9b},
+ {0x83e2, 0xfc},
+ {0x83e3, 0xe9},
+ {0x83e4, 0x9a},
+ {0x83e5, 0xf9},
+ {0x83e6, 0x0f},
+ {0x83e7, 0xd8},
+ {0x83e8, 0xe0},
+ {0x83e9, 0xe4},
+ {0x83ea, 0xc9},
+ {0x83eb, 0xfa},
+ {0x83ec, 0xe4},
+ {0x83ed, 0xcc},
+ {0x83ee, 0xfb},
+ {0x83ef, 0x22},
+ {0x83f0, 0x75},
+ {0x83f1, 0xf0},
+ {0x83f2, 0x10},
+ {0x83f3, 0xef},
+ {0x83f4, 0x2f},
+ {0x83f5, 0xff},
+ {0x83f6, 0xee},
+ {0x83f7, 0x33},
+ {0x83f8, 0xfe},
+ {0x83f9, 0xed},
+ {0x83fa, 0x33},
+ {0x83fb, 0xfd},
+ {0x83fc, 0xcc},
+ {0x83fd, 0x33},
+ {0x83fe, 0xcc},
+ {0x83ff, 0xc8},
+ {0x8400, 0x33},
+ {0x8401, 0xc8},
+ {0x8402, 0x10},
+ {0x8403, 0xd7},
+ {0x8404, 0x07},
+ {0x8405, 0x9b},
+ {0x8406, 0xec},
+ {0x8407, 0x9a},
+ {0x8408, 0xe8},
+ {0x8409, 0x99},
+ {0x840a, 0x40},
+ {0x840b, 0x0a},
+ {0x840c, 0xed},
+ {0x840d, 0x9b},
+ {0x840e, 0xfd},
+ {0x840f, 0xec},
+ {0x8410, 0x9a},
+ {0x8411, 0xfc},
+ {0x8412, 0xe8},
+ {0x8413, 0x99},
+ {0x8414, 0xf8},
+ {0x8415, 0x0f},
+ {0x8416, 0xd5},
+ {0x8417, 0xf0},
+ {0x8418, 0xda},
+ {0x8419, 0xe4},
+ {0x841a, 0xcd},
+ {0x841b, 0xfb},
+ {0x841c, 0xe4},
+ {0x841d, 0xcc},
+ {0x841e, 0xfa},
+ {0x841f, 0xe4},
+ {0x8420, 0xc8},
+ {0x8421, 0xf9},
+ {0x8422, 0x22},
+ {0x8423, 0xeb},
+ {0x8424, 0x9f},
+ {0x8425, 0xf5},
+ {0x8426, 0xf0},
+ {0x8427, 0xea},
+ {0x8428, 0x9e},
+ {0x8429, 0x42},
+ {0x842a, 0xf0},
+ {0x842b, 0xe9},
+ {0x842c, 0x9d},
+ {0x842d, 0x42},
+ {0x842e, 0xf0},
+ {0x842f, 0xe8},
+ {0x8430, 0x9c},
+ {0x8431, 0x45},
+ {0x8432, 0xf0},
+ {0x8433, 0x22},
+ {0x8434, 0xe8},
+ {0x8435, 0x60},
+ {0x8436, 0x0f},
+ {0x8437, 0xef},
+ {0x8438, 0xc3},
+ {0x8439, 0x33},
+ {0x843a, 0xff},
+ {0x843b, 0xee},
+ {0x843c, 0x33},
+ {0x843d, 0xfe},
+ {0x843e, 0xed},
+ {0x843f, 0x33},
+ {0x8440, 0xfd},
+ {0x8441, 0xec},
+ {0x8442, 0x33},
+ {0x8443, 0xfc},
+ {0x8444, 0xd8},
+ {0x8445, 0xf1},
+ {0x8446, 0x22},
+ {0x8447, 0xe4},
+ {0x8448, 0x93},
+ {0x8449, 0xfc},
+ {0x844a, 0x74},
+ {0x844b, 0x01},
+ {0x844c, 0x93},
+ {0x844d, 0xfd},
+ {0x844e, 0x74},
+ {0x844f, 0x02},
+ {0x8450, 0x93},
+ {0x8451, 0xfe},
+ {0x8452, 0x74},
+ {0x8453, 0x03},
+ {0x8454, 0x93},
+ {0x8455, 0xff},
+ {0x8456, 0x22},
+ {0x8457, 0xe6},
+ {0x8458, 0xfb},
+ {0x8459, 0x08},
+ {0x845a, 0xe6},
+ {0x845b, 0xf9},
+ {0x845c, 0x08},
+ {0x845d, 0xe6},
+ {0x845e, 0xfa},
+ {0x845f, 0x08},
+ {0x8460, 0xe6},
+ {0x8461, 0xcb},
+ {0x8462, 0xf8},
+ {0x8463, 0x22},
+ {0x8464, 0xec},
+ {0x8465, 0xf6},
+ {0x8466, 0x08},
+ {0x8467, 0xed},
+ {0x8468, 0xf6},
+ {0x8469, 0x08},
+ {0x846a, 0xee},
+ {0x846b, 0xf6},
+ {0x846c, 0x08},
+ {0x846d, 0xef},
+ {0x846e, 0xf6},
+ {0x846f, 0x22},
+ {0x8470, 0xd0},
+ {0x8471, 0x83},
+ {0x8472, 0xd0},
+ {0x8473, 0x82},
+ {0x8474, 0xe4},
+ {0x8475, 0x93},
+ {0x8476, 0xf6},
+ {0x8477, 0x08},
+ {0x8478, 0x74},
+ {0x8479, 0x01},
+ {0x847a, 0x93},
+ {0x847b, 0xf6},
+ {0x847c, 0x08},
+ {0x847d, 0x74},
+ {0x847e, 0x02},
+ {0x847f, 0x93},
+ {0x8480, 0xf6},
+ {0x8481, 0x08},
+ {0x8482, 0x74},
+ {0x8483, 0x03},
+ {0x8484, 0x93},
+ {0x8485, 0xf6},
+ {0x8486, 0x74},
+ {0x8487, 0x04},
+ {0x8488, 0x73},
+ {0x8489, 0xa4},
+ {0x848a, 0x25},
+ {0x848b, 0x82},
+ {0x848c, 0xf5},
+ {0x848d, 0x82},
+ {0x848e, 0xe5},
+ {0x848f, 0xf0},
+ {0x8490, 0x35},
+ {0x8491, 0x83},
+ {0x8492, 0xf5},
+ {0x8493, 0x83},
+ {0x8494, 0x22},
+ {0x8495, 0xd0},
+ {0x8496, 0x83},
+ {0x8497, 0xd0},
+ {0x8498, 0x82},
+ {0x8499, 0xf8},
+ {0x849a, 0xe4},
+ {0x849b, 0x93},
+ {0x849c, 0x70},
+ {0x849d, 0x12},
+ {0x849e, 0x74},
+ {0x849f, 0x01},
+ {0x84a0, 0x93},
+ {0x84a1, 0x70},
+ {0x84a2, 0x0d},
+ {0x84a3, 0xa3},
+ {0x84a4, 0xa3},
+ {0x84a5, 0x93},
+ {0x84a6, 0xf8},
+ {0x84a7, 0x74},
+ {0x84a8, 0x01},
+ {0x84a9, 0x93},
+ {0x84aa, 0xf5},
+ {0x84ab, 0x82},
+ {0x84ac, 0x88},
+ {0x84ad, 0x83},
+ {0x84ae, 0xe4},
+ {0x84af, 0x73},
+ {0x84b0, 0x74},
+ {0x84b1, 0x02},
+ {0x84b2, 0x93},
+ {0x84b3, 0x68},
+ {0x84b4, 0x60},
+ {0x84b5, 0xef},
+ {0x84b6, 0xa3},
+ {0x84b7, 0xa3},
+ {0x84b8, 0xa3},
+ {0x84b9, 0x80},
+ {0x84ba, 0xdf},
+ {0x84bb, 0x90},
+ {0x84bc, 0x38},
+ {0x84bd, 0x04},
+ {0x84be, 0x78},
+ {0x84bf, 0x45},
+ {0x84c0, 0x12},
+ {0x84c1, 0x09},
+ {0x84c2, 0x1f},
+ {0x84c3, 0x90},
+ {0x84c4, 0x38},
+ {0x84c5, 0x00},
+ {0x84c6, 0xe0},
+ {0x84c7, 0xfe},
+ {0x84c8, 0xa3},
+ {0x84c9, 0xe0},
+ {0x84ca, 0xfd},
+ {0x84cb, 0xed},
+ {0x84cc, 0xff},
+ {0x84cd, 0xc3},
+ {0x84ce, 0x12},
+ {0x84cf, 0x08},
+ {0x84d0, 0xcb},
+ {0x84d1, 0x90},
+ {0x84d2, 0x38},
+ {0x84d3, 0x10},
+ {0x84d4, 0x12},
+ {0x84d5, 0x08},
+ {0x84d6, 0xbf},
+ {0x84d7, 0x90},
+ {0x84d8, 0x38},
+ {0x84d9, 0x06},
+ {0x84da, 0x78},
+ {0x84db, 0x47},
+ {0x84dc, 0x12},
+ {0x84dd, 0x09},
+ {0x84de, 0x1f},
+ {0x84df, 0x90},
+ {0x84e0, 0x38},
+ {0x84e1, 0x02},
+ {0x84e2, 0xe0},
+ {0x84e3, 0xfe},
+ {0x84e4, 0xa3},
+ {0x84e5, 0xe0},
+ {0x84e6, 0xfd},
+ {0x84e7, 0xed},
+ {0x84e8, 0xff},
+ {0x84e9, 0xc3},
+ {0x84ea, 0x12},
+ {0x84eb, 0x08},
+ {0x84ec, 0xcb},
+ {0x84ed, 0x90},
+ {0x84ee, 0x38},
+ {0x84ef, 0x12},
+ {0x84f0, 0x12},
+ {0x84f1, 0x08},
+ {0x84f2, 0xbf},
+ {0x84f3, 0xa3},
+ {0x84f4, 0xe0},
+ {0x84f5, 0xb4},
+ {0x84f6, 0x31},
+ {0x84f7, 0x07},
+ {0x84f8, 0x78},
+ {0x84f9, 0x45},
+ {0x84fa, 0x79},
+ {0x84fb, 0x45},
+ {0x84fc, 0x12},
+ {0x84fd, 0x09},
+ {0x84fe, 0x2a},
+ {0x84ff, 0x90},
+ {0x8500, 0x38},
+ {0x8501, 0x14},
+ {0x8502, 0xe0},
+ {0x8503, 0xb4},
+ {0x8504, 0x71},
+ {0x8505, 0x15},
+ {0x8506, 0x78},
+ {0x8507, 0x45},
+ {0x8508, 0xe6},
+ {0x8509, 0xfe},
+ {0x850a, 0x08},
+ {0x850b, 0xe6},
+ {0x850c, 0x78},
+ {0x850d, 0x02},
+ {0x850e, 0xce},
+ {0x850f, 0xc3},
+ {0x8510, 0x13},
+ {0x8511, 0xce},
+ {0x8512, 0x13},
+ {0x8513, 0xd8},
+ {0x8514, 0xf9},
+ {0x8515, 0x79},
+ {0x8516, 0x46},
+ {0x8517, 0xf7},
+ {0x8518, 0xee},
+ {0x8519, 0x19},
+ {0x851a, 0xf7},
+ {0x851b, 0x90},
+ {0x851c, 0x38},
+ {0x851d, 0x15},
+ {0x851e, 0xe0},
+ {0x851f, 0xb4},
+ {0x8520, 0x31},
+ {0x8521, 0x07},
+ {0x8522, 0x78},
+ {0x8523, 0x47},
+ {0x8524, 0x79},
+ {0x8525, 0x47},
+ {0x8526, 0x12},
+ {0x8527, 0x09},
+ {0x8528, 0x2a},
+ {0x8529, 0x90},
+ {0x852a, 0x38},
+ {0x852b, 0x15},
+ {0x852c, 0xe0},
+ {0x852d, 0xb4},
+ {0x852e, 0x71},
+ {0x852f, 0x15},
+ {0x8530, 0x78},
+ {0x8531, 0x47},
+ {0x8532, 0xe6},
+ {0x8533, 0xfe},
+ {0x8534, 0x08},
+ {0x8535, 0xe6},
+ {0x8536, 0x78},
+ {0x8537, 0x02},
+ {0x8538, 0xce},
+ {0x8539, 0xc3},
+ {0x853a, 0x13},
+ {0x853b, 0xce},
+ {0x853c, 0x13},
+ {0x853d, 0xd8},
+ {0x853e, 0xf9},
+ {0x853f, 0x79},
+ {0x8540, 0x48},
+ {0x8541, 0xf7},
+ {0x8542, 0xee},
+ {0x8543, 0x19},
+ {0x8544, 0xf7},
+ {0x8545, 0x79},
+ {0x8546, 0x45},
+ {0x8547, 0x12},
+ {0x8548, 0x08},
+ {0x8549, 0xfb},
+ {0x854a, 0x09},
+ {0x854b, 0x12},
+ {0x854c, 0x08},
+ {0x854d, 0xfb},
+ {0x854e, 0xaf},
+ {0x854f, 0x3a},
+ {0x8550, 0x12},
+ {0x8551, 0x08},
+ {0x8552, 0xb0},
+ {0x8553, 0x7d},
+ {0x8554, 0x50},
+ {0x8555, 0x12},
+ {0x8556, 0x02},
+ {0x8557, 0xb1},
+ {0x8558, 0x78},
+ {0x8559, 0x4d},
+ {0x855a, 0xa6},
+ {0x855b, 0x06},
+ {0x855c, 0x08},
+ {0x855d, 0xa6},
+ {0x855e, 0x07},
+ {0x855f, 0xaf},
+ {0x8560, 0x38},
+ {0x8561, 0x12},
+ {0x8562, 0x08},
+ {0x8563, 0xb0},
+ {0x8564, 0x7d},
+ {0x8565, 0x50},
+ {0x8566, 0x12},
+ {0x8567, 0x02},
+ {0x8568, 0xb1},
+ {0x8569, 0x78},
+ {0x856a, 0x49},
+ {0x856b, 0xa6},
+ {0x856c, 0x06},
+ {0x856d, 0x08},
+ {0x856e, 0xa6},
+ {0x856f, 0x07},
+ {0x8570, 0xaf},
+ {0x8571, 0x3b},
+ {0x8572, 0x78},
+ {0x8573, 0x47},
+ {0x8574, 0x12},
+ {0x8575, 0x08},
+ {0x8576, 0xb2},
+ {0x8577, 0x7d},
+ {0x8578, 0x3c},
+ {0x8579, 0x12},
+ {0x857a, 0x02},
+ {0x857b, 0xb1},
+ {0x857c, 0x78},
+ {0x857d, 0x4f},
+ {0x857e, 0xa6},
+ {0x857f, 0x06},
+ {0x8580, 0x08},
+ {0x8581, 0xa6},
+ {0x8582, 0x07},
+ {0x8583, 0xaf},
+ {0x8584, 0x39},
+ {0x8585, 0x7e},
+ {0x8586, 0x00},
+ {0x8587, 0x78},
+ {0x8588, 0x47},
+ {0x8589, 0x12},
+ {0x858a, 0x08},
+ {0x858b, 0xb4},
+ {0x858c, 0x7d},
+ {0x858d, 0x3c},
+ {0x858e, 0x12},
+ {0x858f, 0x02},
+ {0x8590, 0xb1},
+ {0x8591, 0x78},
+ {0x8592, 0x4b},
+ {0x8593, 0xa6},
+ {0x8594, 0x06},
+ {0x8595, 0x08},
+ {0x8596, 0xa6},
+ {0x8597, 0x07},
+ {0x8598, 0xc3},
+ {0x8599, 0x78},
+ {0x859a, 0x4e},
+ {0x859b, 0xe6},
+ {0x859c, 0x94},
+ {0x859d, 0x08},
+ {0x859e, 0x18},
+ {0x859f, 0xe6},
+ {0x85a0, 0x94},
+ {0x85a1, 0x00},
+ {0x85a2, 0x50},
+ {0x85a3, 0x05},
+ {0x85a4, 0x76},
+ {0x85a5, 0x00},
+ {0x85a6, 0x08},
+ {0x85a7, 0x76},
+ {0x85a8, 0x08},
+ {0x85a9, 0xc3},
+ {0x85aa, 0x78},
+ {0x85ab, 0x50},
+ {0x85ac, 0xe6},
+ {0x85ad, 0x94},
+ {0x85ae, 0x08},
+ {0x85af, 0x18},
+ {0x85b0, 0xe6},
+ {0x85b1, 0x94},
+ {0x85b2, 0x00},
+ {0x85b3, 0x50},
+ {0x85b4, 0x05},
+ {0x85b5, 0x76},
+ {0x85b6, 0x00},
+ {0x85b7, 0x08},
+ {0x85b8, 0x76},
+ {0x85b9, 0x08},
+ {0x85ba, 0x78},
+ {0x85bb, 0x4d},
+ {0x85bc, 0x12},
+ {0x85bd, 0x08},
+ {0x85be, 0xe8},
+ {0x85bf, 0xff},
+ {0x85c0, 0xc3},
+ {0x85c1, 0x78},
+ {0x85c2, 0x4a},
+ {0x85c3, 0xe6},
+ {0x85c4, 0x9f},
+ {0x85c5, 0xff},
+ {0x85c6, 0x18},
+ {0x85c7, 0xe6},
+ {0x85c8, 0x9e},
+ {0x85c9, 0x78},
+ {0x85ca, 0x51},
+ {0x85cb, 0x12},
+ {0x85cc, 0x08},
+ {0x85cd, 0xdf},
+ {0x85ce, 0xff},
+ {0x85cf, 0xc3},
+ {0x85d0, 0x78},
+ {0x85d1, 0x4c},
+ {0x85d2, 0xe6},
+ {0x85d3, 0x9f},
+ {0x85d4, 0xff},
+ {0x85d5, 0x18},
+ {0x85d6, 0xe6},
+ {0x85d7, 0x9e},
+ {0x85d8, 0xfe},
+ {0x85d9, 0xe4},
+ {0x85da, 0xfc},
+ {0x85db, 0xfd},
+ {0x85dc, 0x78},
+ {0x85dd, 0x55},
+ {0x85de, 0x12},
+ {0x85df, 0x04},
+ {0x85e0, 0x64},
+ {0x85e1, 0x78},
+ {0x85e2, 0x4d},
+ {0x85e3, 0x12},
+ {0x85e4, 0x08},
+ {0x85e5, 0xe8},
+ {0x85e6, 0x78},
+ {0x85e7, 0x4a},
+ {0x85e8, 0x26},
+ {0x85e9, 0xff},
+ {0x85ea, 0xee},
+ {0x85eb, 0x18},
+ {0x85ec, 0x36},
+ {0x85ed, 0x78},
+ {0x85ee, 0x59},
+ {0x85ef, 0x12},
+ {0x85f0, 0x08},
+ {0x85f1, 0xdf},
+ {0x85f2, 0x78},
+ {0x85f3, 0x4c},
+ {0x85f4, 0x26},
+ {0x85f5, 0xff},
+ {0x85f6, 0xee},
+ {0x85f7, 0x18},
+ {0x85f8, 0x36},
+ {0x85f9, 0xfe},
+ {0x85fa, 0xe4},
+ {0x85fb, 0xfc},
+ {0x85fc, 0xfd},
+ {0x85fd, 0x78},
+ {0x85fe, 0x5d},
+ {0x85ff, 0x12},
+ {0x8600, 0x04},
+ {0x8601, 0x64},
+ {0x8602, 0x78},
+ {0x8603, 0x51},
+ {0x8604, 0x12},
+ {0x8605, 0x09},
+ {0x8606, 0x13},
+ {0x8607, 0x50},
+ {0x8608, 0x09},
+ {0x8609, 0x78},
+ {0x860a, 0x51},
+ {0x860b, 0x12},
+ {0x860c, 0x04},
+ {0x860d, 0x70},
+ {0x860e, 0x00},
+ {0x860f, 0x00},
+ {0x8610, 0x00},
+ {0x8611, 0x00},
+ {0x8612, 0x78},
+ {0x8613, 0x55},
+ {0x8614, 0x12},
+ {0x8615, 0x09},
+ {0x8616, 0x13},
+ {0x8617, 0x50},
+ {0x8618, 0x09},
+ {0x8619, 0x78},
+ {0x861a, 0x55},
+ {0x861b, 0x12},
+ {0x861c, 0x04},
+ {0x861d, 0x70},
+ {0x861e, 0x00},
+ {0x861f, 0x00},
+ {0x8620, 0x00},
+ {0x8621, 0x00},
+ {0x8622, 0x12},
+ {0x8623, 0x08},
+ {0x8624, 0xf0},
+ {0x8625, 0x78},
+ {0x8626, 0x59},
+ {0x8627, 0x12},
+ {0x8628, 0x04},
+ {0x8629, 0x57},
+ {0x862a, 0xd3},
+ {0x862b, 0x12},
+ {0x862c, 0x04},
+ {0x862d, 0x23},
+ {0x862e, 0x40},
+ {0x862f, 0x08},
+ {0x8630, 0x12},
+ {0x8631, 0x08},
+ {0x8632, 0xf0},
+ {0x8633, 0x78},
+ {0x8634, 0x59},
+ {0x8635, 0x12},
+ {0x8636, 0x04},
+ {0x8637, 0x64},
+ {0x8638, 0x78},
+ {0x8639, 0x47},
+ {0x863a, 0x12},
+ {0x863b, 0x08},
+ {0x863c, 0xf2},
+ {0x863d, 0x78},
+ {0x863e, 0x5d},
+ {0x863f, 0x12},
+ {0x8640, 0x04},
+ {0x8641, 0x57},
+ {0x8642, 0xd3},
+ {0x8643, 0x12},
+ {0x8644, 0x04},
+ {0x8645, 0x23},
+ {0x8646, 0x40},
+ {0x8647, 0x0a},
+ {0x8648, 0x78},
+ {0x8649, 0x47},
+ {0x864a, 0x12},
+ {0x864b, 0x08},
+ {0x864c, 0xf2},
+ {0x864d, 0x78},
+ {0x864e, 0x5d},
+ {0x864f, 0x12},
+ {0x8650, 0x04},
+ {0x8651, 0x64},
+ {0x8652, 0xe4},
+ {0x8653, 0xfd},
+ {0x8654, 0x78},
+ {0x8655, 0x54},
+ {0x8656, 0x12},
+ {0x8657, 0x09},
+ {0x8658, 0x0b},
+ {0x8659, 0x24},
+ {0x865a, 0x01},
+ {0x865b, 0x12},
+ {0x865c, 0x08},
+ {0x865d, 0xd3},
+ {0x865e, 0x78},
+ {0x865f, 0x58},
+ {0x8660, 0x12},
+ {0x8661, 0x09},
+ {0x8662, 0x0b},
+ {0x8663, 0x24},
+ {0x8664, 0x02},
+ {0x8665, 0x12},
+ {0x8666, 0x08},
+ {0x8667, 0xd3},
+ {0x8668, 0x78},
+ {0x8669, 0x5c},
+ {0x866a, 0x12},
+ {0x866b, 0x09},
+ {0x866c, 0x0b},
+ {0x866d, 0x24},
+ {0x866e, 0x03},
+ {0x866f, 0x12},
+ {0x8670, 0x08},
+ {0x8671, 0xd3},
+ {0x8672, 0x78},
+ {0x8673, 0x60},
+ {0x8674, 0x12},
+ {0x8675, 0x09},
+ {0x8676, 0x0b},
+ {0x8677, 0x24},
+ {0x8678, 0x04},
+ {0x8679, 0x12},
+ {0x867a, 0x08},
+ {0x867b, 0xd3},
+ {0x867c, 0x0d},
+ {0x867d, 0xbd},
+ {0x867e, 0x05},
+ {0x867f, 0xd4},
+ {0x8680, 0xc2},
+ {0x8681, 0x0e},
+ {0x8682, 0xc2},
+ {0x8683, 0x06},
+ {0x8684, 0x22},
+ {0x8685, 0x85},
+ {0x8686, 0x08},
+ {0x8687, 0x36},
+ {0x8688, 0x90},
+ {0x8689, 0x30},
+ {0x868a, 0x24},
+ {0x868b, 0xe0},
+ {0x868c, 0xf5},
+ {0x868d, 0x32},
+ {0x868e, 0xa3},
+ {0x868f, 0xe0},
+ {0x8690, 0xf5},
+ {0x8691, 0x33},
+ {0x8692, 0xa3},
+ {0x8693, 0xe0},
+ {0x8694, 0xf5},
+ {0x8695, 0x34},
+ {0x8696, 0xa3},
+ {0x8697, 0xe0},
+ {0x8698, 0xf5},
+ {0x8699, 0x35},
+ {0x869a, 0xa3},
+ {0x869b, 0xe0},
+ {0x869c, 0xf5},
+ {0x869d, 0x31},
+ {0x869e, 0xd2},
+ {0x869f, 0x33},
+ {0x86a0, 0xe5},
+ {0x86a1, 0x36},
+ {0x86a2, 0x12},
+ {0x86a3, 0x04},
+ {0x86a4, 0x95},
+ {0x86a5, 0x06},
+ {0x86a6, 0xdf},
+ {0x86a7, 0x03},
+ {0x86a8, 0x06},
+ {0x86a9, 0xe3},
+ {0x86aa, 0x04},
+ {0x86ab, 0x06},
+ {0x86ac, 0xe9},
+ {0x86ad, 0x07},
+ {0x86ae, 0x06},
+ {0x86af, 0xf1},
+ {0x86b0, 0x08},
+ {0x86b1, 0x07},
+ {0x86b2, 0x14},
+ {0x86b3, 0x18},
+ {0x86b4, 0x07},
+ {0x86b5, 0x2a},
+ {0x86b6, 0x19},
+ {0x86b7, 0x07},
+ {0x86b8, 0x01},
+ {0x86b9, 0x1a},
+ {0x86ba, 0x07},
+ {0x86bb, 0x0c},
+ {0x86bc, 0x1b},
+ {0x86bd, 0x07},
+ {0x86be, 0x4e},
+ {0x86bf, 0x80},
+ {0x86c0, 0x07},
+ {0x86c1, 0x51},
+ {0x86c2, 0x81},
+ {0x86c3, 0x07},
+ {0x86c4, 0x6d},
+ {0x86c5, 0x8f},
+ {0x86c6, 0x07},
+ {0x86c7, 0x5c},
+ {0x86c8, 0x90},
+ {0x86c9, 0x07},
+ {0x86ca, 0x6d},
+ {0x86cb, 0x91},
+ {0x86cc, 0x07},
+ {0x86cd, 0x6d},
+ {0x86ce, 0x92},
+ {0x86cf, 0x07},
+ {0x86d0, 0x6d},
+ {0x86d1, 0x93},
+ {0x86d2, 0x07},
+ {0x86d3, 0x6d},
+ {0x86d4, 0x94},
+ {0x86d5, 0x07},
+ {0x86d6, 0x6d},
+ {0x86d7, 0x98},
+ {0x86d8, 0x07},
+ {0x86d9, 0x6a},
+ {0x86da, 0x9f},
+ {0x86db, 0x00},
+ {0x86dc, 0x00},
+ {0x86dd, 0x07},
+ {0x86de, 0x88},
+ {0x86df, 0x12},
+ {0x86e0, 0x0a},
+ {0x86e1, 0xb8},
+ {0x86e2, 0x22},
+ {0x86e3, 0x12},
+ {0x86e4, 0x0a},
+ {0x86e5, 0xb8},
+ {0x86e6, 0xd2},
+ {0x86e7, 0x03},
+ {0x86e8, 0x22},
+ {0x86e9, 0xa2},
+ {0x86ea, 0x36},
+ {0x86eb, 0xe4},
+ {0x86ec, 0x33},
+ {0x86ed, 0xf5},
+ {0x86ee, 0x31},
+ {0x86ef, 0x80},
+ {0x86f0, 0x7c},
+ {0x86f1, 0xc2},
+ {0x86f2, 0x01},
+ {0x86f3, 0xc2},
+ {0x86f4, 0x02},
+ {0x86f5, 0xc2},
+ {0x86f6, 0x03},
+ {0x86f7, 0x12},
+ {0x86f8, 0x09},
+ {0x86f9, 0x34},
+ {0x86fa, 0x75},
+ {0x86fb, 0x3f},
+ {0x86fc, 0x70},
+ {0x86fd, 0xd2},
+ {0x86fe, 0x34},
+ {0x86ff, 0x80},
+ {0x8700, 0x6c},
+ {0x8701, 0x85},
+ {0x8702, 0x35},
+ {0x8703, 0x3d},
+ {0x8704, 0x85},
+ {0x8705, 0x31},
+ {0x8706, 0x3e},
+ {0x8707, 0x12},
+ {0x8708, 0x08},
+ {0x8709, 0x1d},
+ {0x870a, 0x80},
+ {0x870b, 0x61},
+ {0x870c, 0x85},
+ {0x870d, 0x3d},
+ {0x870e, 0x35},
+ {0x870f, 0x85},
+ {0x8710, 0x3e},
+ {0x8711, 0x31},
+ {0x8712, 0x80},
+ {0x8713, 0x59},
+ {0x8714, 0xe4},
+ {0x8715, 0xf5},
+ {0x8716, 0x22},
+ {0x8717, 0xf5},
+ {0x8718, 0x23},
+ {0x8719, 0x85},
+ {0x871a, 0x35},
+ {0x871b, 0x1e},
+ {0x871c, 0x85},
+ {0x871d, 0x34},
+ {0x871e, 0x1d},
+ {0x871f, 0x85},
+ {0x8720, 0x33},
+ {0x8721, 0x1c},
+ {0x8722, 0x85},
+ {0x8723, 0x32},
+ {0x8724, 0x1b},
+ {0x8725, 0x12},
+ {0x8726, 0x0a},
+ {0x8727, 0x8a},
+ {0x8728, 0x80},
+ {0x8729, 0x1f},
+ {0x872a, 0x75},
+ {0x872b, 0x22},
+ {0x872c, 0x00},
+ {0x872d, 0x75},
+ {0x872e, 0x23},
+ {0x872f, 0x01},
+ {0x8730, 0x74},
+ {0x8731, 0xff},
+ {0x8732, 0xf5},
+ {0x8733, 0x1a},
+ {0x8734, 0xf5},
+ {0x8735, 0x19},
+ {0x8736, 0xf5},
+ {0x8737, 0x18},
+ {0x8738, 0xf5},
+ {0x8739, 0x17},
+ {0x873a, 0x12},
+ {0x873b, 0x0a},
+ {0x873c, 0x8a},
+ {0x873d, 0x85},
+ {0x873e, 0x1a},
+ {0x873f, 0x35},
+ {0x8740, 0x85},
+ {0x8741, 0x19},
+ {0x8742, 0x34},
+ {0x8743, 0x85},
+ {0x8744, 0x18},
+ {0x8745, 0x33},
+ {0x8746, 0x85},
+ {0x8747, 0x17},
+ {0x8748, 0x32},
+ {0x8749, 0xe4},
+ {0x874a, 0xf5},
+ {0x874b, 0x31},
+ {0x874c, 0x80},
+ {0x874d, 0x1f},
+ {0x874e, 0x02},
+ {0x874f, 0x0a},
+ {0x8750, 0xef},
+ {0x8751, 0x85},
+ {0x8752, 0x32},
+ {0x8753, 0x38},
+ {0x8754, 0x85},
+ {0x8755, 0x33},
+ {0x8756, 0x39},
+ {0x8757, 0x12},
+ {0x8758, 0x04},
+ {0x8759, 0xbb},
+ {0x875a, 0x80},
+ {0x875b, 0x11},
+ {0x875c, 0x85},
+ {0x875d, 0x35},
+ {0x875e, 0x3b},
+ {0x875f, 0x85},
+ {0x8760, 0x34},
+ {0x8761, 0x3a},
+ {0x8762, 0x85},
+ {0x8763, 0x33},
+ {0x8764, 0x39},
+ {0x8765, 0x85},
+ {0x8766, 0x32},
+ {0x8767, 0x38},
+ {0x8768, 0x80},
+ {0x8769, 0x03},
+ {0x876a, 0x02},
+ {0x876b, 0x04},
+ {0x876c, 0xbb},
+ {0x876d, 0x90},
+ {0x876e, 0x30},
+ {0x876f, 0x24},
+ {0x8770, 0xe5},
+ {0x8771, 0x32},
+ {0x8772, 0xf0},
+ {0x8773, 0xa3},
+ {0x8774, 0xe5},
+ {0x8775, 0x33},
+ {0x8776, 0xf0},
+ {0x8777, 0xa3},
+ {0x8778, 0xe5},
+ {0x8779, 0x34},
+ {0x877a, 0xf0},
+ {0x877b, 0xa3},
+ {0x877c, 0xe5},
+ {0x877d, 0x35},
+ {0x877e, 0xf0},
+ {0x877f, 0xa3},
+ {0x8780, 0xe5},
+ {0x8781, 0x31},
+ {0x8782, 0xf0},
+ {0x8783, 0x90},
+ {0x8784, 0x30},
+ {0x8785, 0x23},
+ {0x8786, 0xe4},
+ {0x8787, 0xf0},
+ {0x8788, 0x22},
+ {0x8789, 0xc0},
+ {0x878a, 0xe0},
+ {0x878b, 0xc0},
+ {0x878c, 0x83},
+ {0x878d, 0xc0},
+ {0x878e, 0x82},
+ {0x878f, 0xc0},
+ {0x8790, 0xd0},
+ {0x8791, 0x90},
+ {0x8792, 0x3f},
+ {0x8793, 0x0c},
+ {0x8794, 0xe0},
+ {0x8795, 0xf5},
+ {0x8796, 0x27},
+ {0x8797, 0xe5},
+ {0x8798, 0x27},
+ {0x8799, 0x30},
+ {0x879a, 0xe3},
+ {0x879b, 0x42},
+ {0x879c, 0x30},
+ {0x879d, 0x35},
+ {0x879e, 0x34},
+ {0x879f, 0x90},
+ {0x87a0, 0x60},
+ {0x87a1, 0x19},
+ {0x87a2, 0xe0},
+ {0x87a3, 0xf5},
+ {0x87a4, 0x0a},
+ {0x87a5, 0xa3},
+ {0x87a6, 0xe0},
+ {0x87a7, 0xf5},
+ {0x87a8, 0x0b},
+ {0x87a9, 0x30},
+ {0x87aa, 0x01},
+ {0x87ab, 0x06},
+ {0x87ac, 0x30},
+ {0x87ad, 0x32},
+ {0x87ae, 0x03},
+ {0x87af, 0xd3},
+ {0x87b0, 0x80},
+ {0x87b1, 0x01},
+ {0x87b2, 0xc3},
+ {0x87b3, 0x92},
+ {0x87b4, 0x09},
+ {0x87b5, 0x30},
+ {0x87b6, 0x02},
+ {0x87b7, 0x06},
+ {0x87b8, 0x30},
+ {0x87b9, 0x32},
+ {0x87ba, 0x03},
+ {0x87bb, 0xd3},
+ {0x87bc, 0x80},
+ {0x87bd, 0x01},
+ {0x87be, 0xc3},
+ {0x87bf, 0x92},
+ {0x87c0, 0x0a},
+ {0x87c1, 0x30},
+ {0x87c2, 0x32},
+ {0x87c3, 0x0c},
+ {0x87c4, 0x30},
+ {0x87c5, 0x03},
+ {0x87c6, 0x09},
+ {0x87c7, 0x20},
+ {0x87c8, 0x02},
+ {0x87c9, 0x06},
+ {0x87ca, 0x20},
+ {0x87cb, 0x01},
+ {0x87cc, 0x03},
+ {0x87cd, 0xd3},
+ {0x87ce, 0x80},
+ {0x87cf, 0x01},
+ {0x87d0, 0xc3},
+ {0x87d1, 0x92},
+ {0x87d2, 0x0b},
+ {0x87d3, 0x90},
+ {0x87d4, 0x30},
+ {0x87d5, 0x01},
+ {0x87d6, 0xe0},
+ {0x87d7, 0x44},
+ {0x87d8, 0x40},
+ {0x87d9, 0xf0},
+ {0x87da, 0xe0},
+ {0x87db, 0x54},
+ {0x87dc, 0xbf},
+ {0x87dd, 0xf0},
+ {0x87de, 0xe5},
+ {0x87df, 0x27},
+ {0x87e0, 0x30},
+ {0x87e1, 0xe1},
+ {0x87e2, 0x14},
+ {0x87e3, 0x30},
+ {0x87e4, 0x33},
+ {0x87e5, 0x11},
+ {0x87e6, 0x90},
+ {0x87e7, 0x30},
+ {0x87e8, 0x22},
+ {0x87e9, 0xe0},
+ {0x87ea, 0xf5},
+ {0x87eb, 0x08},
+ {0x87ec, 0xe4},
+ {0x87ed, 0xf0},
+ {0x87ee, 0x30},
+ {0x87ef, 0x00},
+ {0x87f0, 0x03},
+ {0x87f1, 0xd3},
+ {0x87f2, 0x80},
+ {0x87f3, 0x01},
+ {0x87f4, 0xc3},
+ {0x87f5, 0x92},
+ {0x87f6, 0x08},
+ {0x87f7, 0xe5},
+ {0x87f8, 0x27},
+ {0x87f9, 0x30},
+ {0x87fa, 0xe5},
+ {0x87fb, 0x12},
+ {0x87fc, 0x90},
+ {0x87fd, 0x56},
+ {0x87fe, 0x90},
+ {0x87ff, 0xe0},
+ {0x8800, 0xf5},
+ {0x8801, 0x09},
+ {0x8802, 0x30},
+ {0x8803, 0x30},
+ {0x8804, 0x09},
+ {0x8805, 0x30},
+ {0x8806, 0x05},
+ {0x8807, 0x03},
+ {0x8808, 0xd3},
+ {0x8809, 0x80},
+ {0x880a, 0x01},
+ {0x880b, 0xc3},
+ {0x880c, 0x92},
+ {0x880d, 0x0d},
+ {0x880e, 0x90},
+ {0x880f, 0x3f},
+ {0x8810, 0x0c},
+ {0x8811, 0xe5},
+ {0x8812, 0x27},
+ {0x8813, 0xf0},
+ {0x8814, 0xd0},
+ {0x8815, 0xd0},
+ {0x8816, 0xd0},
+ {0x8817, 0x82},
+ {0x8818, 0xd0},
+ {0x8819, 0x83},
+ {0x881a, 0xd0},
+ {0x881b, 0xe0},
+ {0x881c, 0x32},
+ {0x881d, 0x90},
+ {0x881e, 0x0e},
+ {0x881f, 0x7d},
+ {0x8820, 0xe4},
+ {0x8821, 0x93},
+ {0x8822, 0xfe},
+ {0x8823, 0x74},
+ {0x8824, 0x01},
+ {0x8825, 0x93},
+ {0x8826, 0xff},
+ {0x8827, 0xc3},
+ {0x8828, 0x90},
+ {0x8829, 0x0e},
+ {0x882a, 0x7b},
+ {0x882b, 0x74},
+ {0x882c, 0x01},
+ {0x882d, 0x93},
+ {0x882e, 0x9f},
+ {0x882f, 0xff},
+ {0x8830, 0xe4},
+ {0x8831, 0x93},
+ {0x8832, 0x9e},
+ {0x8833, 0xfe},
+ {0x8834, 0xe4},
+ {0x8835, 0x8f},
+ {0x8836, 0x30},
+ {0x8837, 0x8e},
+ {0x8838, 0x2f},
+ {0x8839, 0xf5},
+ {0x883a, 0x2e},
+ {0x883b, 0xf5},
+ {0x883c, 0x2d},
+ {0x883d, 0xab},
+ {0x883e, 0x30},
+ {0x883f, 0xaa},
+ {0x8840, 0x2f},
+ {0x8841, 0xa9},
+ {0x8842, 0x2e},
+ {0x8843, 0xa8},
+ {0x8844, 0x2d},
+ {0x8845, 0xaf},
+ {0x8846, 0x3e},
+ {0x8847, 0xfc},
+ {0x8848, 0xfd},
+ {0x8849, 0xfe},
+ {0x884a, 0x12},
+ {0x884b, 0x03},
+ {0x884c, 0x06},
+ {0x884d, 0x12},
+ {0x884e, 0x0a},
+ {0x884f, 0xd4},
+ {0x8850, 0xe4},
+ {0x8851, 0x7b},
+ {0x8852, 0xff},
+ {0x8853, 0xfa},
+ {0x8854, 0xf9},
+ {0x8855, 0xf8},
+ {0x8856, 0x12},
+ {0x8857, 0x03},
+ {0x8858, 0x91},
+ {0x8859, 0x12},
+ {0x885a, 0x0a},
+ {0x885b, 0xd4},
+ {0x885c, 0x90},
+ {0x885d, 0x0e},
+ {0x885e, 0x69},
+ {0x885f, 0xe4},
+ {0x8860, 0x12},
+ {0x8861, 0x0a},
+ {0x8862, 0xe9},
+ {0x8863, 0x12},
+ {0x8864, 0x0a},
+ {0x8865, 0xd4},
+ {0x8866, 0xe4},
+ {0x8867, 0x85},
+ {0x8868, 0x3d},
+ {0x8869, 0x2c},
+ {0x886a, 0xf5},
+ {0x886b, 0x2b},
+ {0x886c, 0xf5},
+ {0x886d, 0x2a},
+ {0x886e, 0xf5},
+ {0x886f, 0x29},
+ {0x8870, 0xaf},
+ {0x8871, 0x2c},
+ {0x8872, 0xae},
+ {0x8873, 0x2b},
+ {0x8874, 0xad},
+ {0x8875, 0x2a},
+ {0x8876, 0xac},
+ {0x8877, 0x29},
+ {0x8878, 0xa3},
+ {0x8879, 0x12},
+ {0x887a, 0x0a},
+ {0x887b, 0xe9},
+ {0x887c, 0x8f},
+ {0x887d, 0x2c},
+ {0x887e, 0x8e},
+ {0x887f, 0x2b},
+ {0x8880, 0x8d},
+ {0x8881, 0x2a},
+ {0x8882, 0x8c},
+ {0x8883, 0x29},
+ {0x8884, 0xe5},
+ {0x8885, 0x30},
+ {0x8886, 0x45},
+ {0x8887, 0x2c},
+ {0x8888, 0xf5},
+ {0x8889, 0x30},
+ {0x888a, 0xe5},
+ {0x888b, 0x2f},
+ {0x888c, 0x45},
+ {0x888d, 0x2b},
+ {0x888e, 0xf5},
+ {0x888f, 0x2f},
+ {0x8890, 0xe5},
+ {0x8891, 0x2e},
+ {0x8892, 0x45},
+ {0x8893, 0x2a},
+ {0x8894, 0xf5},
+ {0x8895, 0x2e},
+ {0x8896, 0xe5},
+ {0x8897, 0x2d},
+ {0x8898, 0x45},
+ {0x8899, 0x29},
+ {0x889a, 0xf5},
+ {0x889b, 0x2d},
+ {0x889c, 0xe4},
+ {0x889d, 0xf5},
+ {0x889e, 0x22},
+ {0x889f, 0xf5},
+ {0x88a0, 0x23},
+ {0x88a1, 0x85},
+ {0x88a2, 0x30},
+ {0x88a3, 0x1e},
+ {0x88a4, 0x85},
+ {0x88a5, 0x2f},
+ {0x88a6, 0x1d},
+ {0x88a7, 0x85},
+ {0x88a8, 0x2e},
+ {0x88a9, 0x1c},
+ {0x88aa, 0x85},
+ {0x88ab, 0x2d},
+ {0x88ac, 0x1b},
+ {0x88ad, 0x02},
+ {0x88ae, 0x0a},
+ {0x88af, 0x8a},
+ {0x88b0, 0x78},
+ {0x88b1, 0x45},
+ {0x88b2, 0x7e},
+ {0x88b3, 0x00},
+ {0x88b4, 0xe6},
+ {0x88b5, 0xfc},
+ {0x88b6, 0x08},
+ {0x88b7, 0xe6},
+ {0x88b8, 0xfd},
+ {0x88b9, 0x12},
+ {0x88ba, 0x02},
+ {0x88bb, 0x9f},
+ {0x88bc, 0x7c},
+ {0x88bd, 0x00},
+ {0x88be, 0x22},
+ {0x88bf, 0xe0},
+ {0x88c0, 0xa3},
+ {0x88c1, 0xe0},
+ {0x88c2, 0x75},
+ {0x88c3, 0xf0},
+ {0x88c4, 0x02},
+ {0x88c5, 0xa4},
+ {0x88c6, 0xff},
+ {0x88c7, 0xae},
+ {0x88c8, 0xf0},
+ {0x88c9, 0xc3},
+ {0x88ca, 0x08},
+ {0x88cb, 0xe6},
+ {0x88cc, 0x9f},
+ {0x88cd, 0xf6},
+ {0x88ce, 0x18},
+ {0x88cf, 0xe6},
+ {0x88d0, 0x9e},
+ {0x88d1, 0xf6},
+ {0x88d2, 0x22},
+ {0x88d3, 0xff},
+ {0x88d4, 0xe5},
+ {0x88d5, 0xf0},
+ {0x88d6, 0x34},
+ {0x88d7, 0x60},
+ {0x88d8, 0x8f},
+ {0x88d9, 0x82},
+ {0x88da, 0xf5},
+ {0x88db, 0x83},
+ {0x88dc, 0xec},
+ {0x88dd, 0xf0},
+ {0x88de, 0x22},
+ {0x88df, 0xfe},
+ {0x88e0, 0xe4},
+ {0x88e1, 0xfc},
+ {0x88e2, 0xfd},
+ {0x88e3, 0x12},
+ {0x88e4, 0x04},
+ {0x88e5, 0x64},
+ {0x88e6, 0x78},
+ {0x88e7, 0x4f},
+ {0x88e8, 0xe6},
+ {0x88e9, 0xc3},
+ {0x88ea, 0x13},
+ {0x88eb, 0xfe},
+ {0x88ec, 0x08},
+ {0x88ed, 0xe6},
+ {0x88ee, 0x13},
+ {0x88ef, 0x22},
+ {0x88f0, 0x78},
+ {0x88f1, 0x45},
+ {0x88f2, 0xe6},
+ {0x88f3, 0xfe},
+ {0x88f4, 0x08},
+ {0x88f5, 0xe6},
+ {0x88f6, 0xff},
+ {0x88f7, 0xe4},
+ {0x88f8, 0xfc},
+ {0x88f9, 0xfd},
+ {0x88fa, 0x22},
+ {0x88fb, 0xe7},
+ {0x88fc, 0xc4},
+ {0x88fd, 0xf8},
+ {0x88fe, 0x54},
+ {0x88ff, 0xf0},
+ {0x8900, 0xc8},
+ {0x8901, 0x68},
+ {0x8902, 0xf7},
+ {0x8903, 0x09},
+ {0x8904, 0xe7},
+ {0x8905, 0xc4},
+ {0x8906, 0x54},
+ {0x8907, 0x0f},
+ {0x8908, 0x48},
+ {0x8909, 0xf7},
+ {0x890a, 0x22},
+ {0x890b, 0xe6},
+ {0x890c, 0xfc},
+ {0x890d, 0xed},
+ {0x890e, 0x75},
+ {0x890f, 0xf0},
+ {0x8910, 0x04},
+ {0x8911, 0xa4},
+ {0x8912, 0x22},
+ {0x8913, 0xe4},
+ {0x8914, 0xff},
+ {0x8915, 0xfe},
+ {0x8916, 0xfd},
+ {0x8917, 0xfc},
+ {0x8918, 0x12},
+ {0x8919, 0x04},
+ {0x891a, 0x57},
+ {0x891b, 0xc3},
+ {0x891c, 0x02},
+ {0x891d, 0x04},
+ {0x891e, 0x23},
+ {0x891f, 0xe0},
+ {0x8920, 0xfe},
+ {0x8921, 0xa3},
+ {0x8922, 0xe0},
+ {0x8923, 0xfd},
+ {0x8924, 0xee},
+ {0x8925, 0xf6},
+ {0x8926, 0xed},
+ {0x8927, 0x08},
+ {0x8928, 0xf6},
+ {0x8929, 0x22},
+ {0x892a, 0xe6},
+ {0x892b, 0xc3},
+ {0x892c, 0x13},
+ {0x892d, 0xf7},
+ {0x892e, 0x08},
+ {0x892f, 0xe6},
+ {0x8930, 0x13},
+ {0x8931, 0x09},
+ {0x8932, 0xf7},
+ {0x8933, 0x22},
+ {0x8934, 0xe4},
+ {0x8935, 0xf5},
+ {0x8936, 0x3e},
+ {0x8937, 0x90},
+ {0x8938, 0x0e},
+ {0x8939, 0x77},
+ {0x893a, 0x93},
+ {0x893b, 0xff},
+ {0x893c, 0xe4},
+ {0x893d, 0x8f},
+ {0x893e, 0x2c},
+ {0x893f, 0xf5},
+ {0x8940, 0x2b},
+ {0x8941, 0xf5},
+ {0x8942, 0x2a},
+ {0x8943, 0xf5},
+ {0x8944, 0x29},
+ {0x8945, 0xaf},
+ {0x8946, 0x2c},
+ {0x8947, 0xae},
+ {0x8948, 0x2b},
+ {0x8949, 0xad},
+ {0x894a, 0x2a},
+ {0x894b, 0xac},
+ {0x894c, 0x29},
+ {0x894d, 0x90},
+ {0x894e, 0x0e},
+ {0x894f, 0x6a},
+ {0x8950, 0x12},
+ {0x8951, 0x0a},
+ {0x8952, 0xe9},
+ {0x8953, 0x8f},
+ {0x8954, 0x2c},
+ {0x8955, 0x8e},
+ {0x8956, 0x2b},
+ {0x8957, 0x8d},
+ {0x8958, 0x2a},
+ {0x8959, 0x8c},
+ {0x895a, 0x29},
+ {0x895b, 0x90},
+ {0x895c, 0x0e},
+ {0x895d, 0x72},
+ {0x895e, 0x12},
+ {0x895f, 0x04},
+ {0x8960, 0x47},
+ {0x8961, 0xef},
+ {0x8962, 0x45},
+ {0x8963, 0x2c},
+ {0x8964, 0xf5},
+ {0x8965, 0x2c},
+ {0x8966, 0xee},
+ {0x8967, 0x45},
+ {0x8968, 0x2b},
+ {0x8969, 0xf5},
+ {0x896a, 0x2b},
+ {0x896b, 0xed},
+ {0x896c, 0x45},
+ {0x896d, 0x2a},
+ {0x896e, 0xf5},
+ {0x896f, 0x2a},
+ {0x8970, 0xec},
+ {0x8971, 0x45},
+ {0x8972, 0x29},
+ {0x8973, 0xf5},
+ {0x8974, 0x29},
+ {0x8975, 0xe4},
+ {0x8976, 0xf5},
+ {0x8977, 0x22},
+ {0x8978, 0xf5},
+ {0x8979, 0x23},
+ {0x897a, 0x85},
+ {0x897b, 0x2c},
+ {0x897c, 0x1e},
+ {0x897d, 0x85},
+ {0x897e, 0x2b},
+ {0x897f, 0x1d},
+ {0x8980, 0x85},
+ {0x8981, 0x2a},
+ {0x8982, 0x1c},
+ {0x8983, 0x85},
+ {0x8984, 0x29},
+ {0x8985, 0x1b},
+ {0x8986, 0x12},
+ {0x8987, 0x0a},
+ {0x8988, 0x8a},
+ {0x8989, 0xe4},
+ {0x898a, 0xf5},
+ {0x898b, 0x22},
+ {0x898c, 0xf5},
+ {0x898d, 0x23},
+ {0x898e, 0x90},
+ {0x898f, 0x0e},
+ {0x8990, 0x72},
+ {0x8991, 0x12},
+ {0x8992, 0x0a},
+ {0x8993, 0xdd},
+ {0x8994, 0x12},
+ {0x8995, 0x0a},
+ {0x8996, 0x8a},
+ {0x8997, 0xe4},
+ {0x8998, 0xf5},
+ {0x8999, 0x22},
+ {0x899a, 0xf5},
+ {0x899b, 0x23},
+ {0x899c, 0x90},
+ {0x899d, 0x0e},
+ {0x899e, 0x6e},
+ {0x899f, 0x12},
+ {0x89a0, 0x0a},
+ {0x89a1, 0xdd},
+ {0x89a2, 0x02},
+ {0x89a3, 0x0a},
+ {0x89a4, 0x8a},
+ {0x89a5, 0x75},
+ {0x89a6, 0x89},
+ {0x89a7, 0x03},
+ {0x89a8, 0x75},
+ {0x89a9, 0xa8},
+ {0x89aa, 0x01},
+ {0x89ab, 0x75},
+ {0x89ac, 0xb8},
+ {0x89ad, 0x04},
+ {0x89ae, 0x75},
+ {0x89af, 0x29},
+ {0x89b0, 0xff},
+ {0x89b1, 0x75},
+ {0x89b2, 0x2a},
+ {0x89b3, 0x0e},
+ {0x89b4, 0x75},
+ {0x89b5, 0x2b},
+ {0x89b6, 0x15},
+ {0x89b7, 0x75},
+ {0x89b8, 0x2c},
+ {0x89b9, 0x0d},
+ {0x89ba, 0x12},
+ {0x89bb, 0x0a},
+ {0x89bc, 0x0e},
+ {0x89bd, 0x12},
+ {0x89be, 0x00},
+ {0x89bf, 0x09},
+ {0x89c0, 0x12},
+ {0x89c1, 0x0a},
+ {0x89c2, 0xef},
+ {0x89c3, 0x12},
+ {0x89c4, 0x00},
+ {0x89c5, 0x06},
+ {0x89c6, 0xd2},
+ {0x89c7, 0x00},
+ {0x89c8, 0xd2},
+ {0x89c9, 0x33},
+ {0x89ca, 0xd2},
+ {0x89cb, 0xaf},
+ {0x89cc, 0x75},
+ {0x89cd, 0x29},
+ {0x89ce, 0xff},
+ {0x89cf, 0x75},
+ {0x89d0, 0x2a},
+ {0x89d1, 0x0e},
+ {0x89d2, 0x75},
+ {0x89d3, 0x2b},
+ {0x89d4, 0x49},
+ {0x89d5, 0x75},
+ {0x89d6, 0x2c},
+ {0x89d7, 0x03},
+ {0x89d8, 0x12},
+ {0x89d9, 0x0a},
+ {0x89da, 0x0e},
+ {0x89db, 0x30},
+ {0x89dc, 0x08},
+ {0x89dd, 0x09},
+ {0x89de, 0xc2},
+ {0x89df, 0x33},
+ {0x89e0, 0x12},
+ {0x89e1, 0x06},
+ {0x89e2, 0x85},
+ {0x89e3, 0xc2},
+ {0x89e4, 0x08},
+ {0x89e5, 0xd2},
+ {0x89e6, 0x33},
+ {0x89e7, 0x30},
+ {0x89e8, 0x09},
+ {0x89e9, 0x09},
+ {0x89ea, 0xc2},
+ {0x89eb, 0x35},
+ {0x89ec, 0x12},
+ {0x89ed, 0x00},
+ {0x89ee, 0x0e},
+ {0x89ef, 0xc2},
+ {0x89f0, 0x09},
+ {0x89f1, 0xd2},
+ {0x89f2, 0x35},
+ {0x89f3, 0x30},
+ {0x89f4, 0x0e},
+ {0x89f5, 0x03},
+ {0x89f6, 0x12},
+ {0x89f7, 0x04},
+ {0x89f8, 0xbb},
+ {0x89f9, 0x30},
+ {0x89fa, 0x34},
+ {0x89fb, 0xdf},
+ {0x89fc, 0x90},
+ {0x89fd, 0x30},
+ {0x89fe, 0x29},
+ {0x89ff, 0xe5},
+ {0x8a00, 0x3f},
+ {0x8a01, 0xf0},
+ {0x8a02, 0xb4},
+ {0x8a03, 0x10},
+ {0x8a04, 0x05},
+ {0x8a05, 0x90},
+ {0x8a06, 0x30},
+ {0x8a07, 0x23},
+ {0x8a08, 0xe4},
+ {0x8a09, 0xf0},
+ {0x8a0a, 0xc2},
+ {0x8a0b, 0x34},
+ {0x8a0c, 0x80},
+ {0x8a0d, 0xcd},
+ {0x8a0e, 0xae},
+ {0x8a0f, 0x2a},
+ {0x8a10, 0xaf},
+ {0x8a11, 0x2b},
+ {0x8a12, 0xe4},
+ {0x8a13, 0xfd},
+ {0x8a14, 0xed},
+ {0x8a15, 0xc3},
+ {0x8a16, 0x95},
+ {0x8a17, 0x2c},
+ {0x8a18, 0x50},
+ {0x8a19, 0x33},
+ {0x8a1a, 0x12},
+ {0x8a1b, 0x0b},
+ {0x8a1c, 0x36},
+ {0x8a1d, 0xe4},
+ {0x8a1e, 0x93},
+ {0x8a1f, 0xf5},
+ {0x8a20, 0x2d},
+ {0x8a21, 0x74},
+ {0x8a22, 0x01},
+ {0x8a23, 0x93},
+ {0x8a24, 0xf5},
+ {0x8a25, 0x2e},
+ {0x8a26, 0x45},
+ {0x8a27, 0x2d},
+ {0x8a28, 0x60},
+ {0x8a29, 0x23},
+ {0x8a2a, 0x85},
+ {0x8a2b, 0x2e},
+ {0x8a2c, 0x82},
+ {0x8a2d, 0x85},
+ {0x8a2e, 0x2d},
+ {0x8a2f, 0x83},
+ {0x8a30, 0xe0},
+ {0x8a31, 0xfc},
+ {0x8a32, 0x12},
+ {0x8a33, 0x0b},
+ {0x8a34, 0x36},
+ {0x8a35, 0x74},
+ {0x8a36, 0x03},
+ {0x8a37, 0x93},
+ {0x8a38, 0x52},
+ {0x8a39, 0x04},
+ {0x8a3a, 0x12},
+ {0x8a3b, 0x0b},
+ {0x8a3c, 0x36},
+ {0x8a3d, 0x74},
+ {0x8a3e, 0x02},
+ {0x8a3f, 0x93},
+ {0x8a40, 0x42},
+ {0x8a41, 0x04},
+ {0x8a42, 0x85},
+ {0x8a43, 0x2e},
+ {0x8a44, 0x82},
+ {0x8a45, 0x85},
+ {0x8a46, 0x2d},
+ {0x8a47, 0x83},
+ {0x8a48, 0xec},
+ {0x8a49, 0xf0},
+ {0x8a4a, 0x0d},
+ {0x8a4b, 0x80},
+ {0x8a4c, 0xc7},
+ {0x8a4d, 0x22},
+ {0x8a4e, 0x78},
+ {0x8a4f, 0xb1},
+ {0x8a50, 0xe6},
+ {0x8a51, 0xd3},
+ {0x8a52, 0x08},
+ {0x8a53, 0xff},
+ {0x8a54, 0xe6},
+ {0x8a55, 0x64},
+ {0x8a56, 0x80},
+ {0x8a57, 0xf8},
+ {0x8a58, 0xef},
+ {0x8a59, 0x64},
+ {0x8a5a, 0x80},
+ {0x8a5b, 0x98},
+ {0x8a5c, 0x22},
+ {0x8a5d, 0x93},
+ {0x8a5e, 0xff},
+ {0x8a5f, 0x7e},
+ {0x8a60, 0x00},
+ {0x8a61, 0xe6},
+ {0x8a62, 0xfc},
+ {0x8a63, 0x08},
+ {0x8a64, 0xe6},
+ {0x8a65, 0xfd},
+ {0x8a66, 0x12},
+ {0x8a67, 0x02},
+ {0x8a68, 0x9f},
+ {0x8a69, 0x78},
+ {0x8a6a, 0xb4},
+ {0x8a6b, 0xe6},
+ {0x8a6c, 0xfc},
+ {0x8a6d, 0x08},
+ {0x8a6e, 0xe6},
+ {0x8a6f, 0xfd},
+ {0x8a70, 0xd3},
+ {0x8a71, 0xef},
+ {0x8a72, 0x9d},
+ {0x8a73, 0xee},
+ {0x8a74, 0x9c},
+ {0x8a75, 0x22},
+ {0x8a76, 0x78},
+ {0x8a77, 0xb0},
+ {0x8a78, 0xd3},
+ {0x8a79, 0xe6},
+ {0x8a7a, 0x64},
+ {0x8a7b, 0x80},
+ {0x8a7c, 0x94},
+ {0x8a7d, 0x80},
+ {0x8a7e, 0x22},
+ {0x8a7f, 0x25},
+ {0x8a80, 0xe0},
+ {0x8a81, 0x24},
+ {0x8a82, 0x0a},
+ {0x8a83, 0xf8},
+ {0x8a84, 0xe6},
+ {0x8a85, 0xfe},
+ {0x8a86, 0x08},
+ {0x8a87, 0xe6},
+ {0x8a88, 0xff},
+ {0x8a89, 0x22},
+ {0x8a8a, 0xa2},
+ {0x8a8b, 0xaf},
+ {0x8a8c, 0x92},
+ {0x8a8d, 0x31},
+ {0x8a8e, 0xc2},
+ {0x8a8f, 0xaf},
+ {0x8a90, 0xe5},
+ {0x8a91, 0x23},
+ {0x8a92, 0x45},
+ {0x8a93, 0x22},
+ {0x8a94, 0x90},
+ {0x8a95, 0x0e},
+ {0x8a96, 0x5d},
+ {0x8a97, 0x60},
+ {0x8a98, 0x0b},
+ {0x8a99, 0x12},
+ {0x8a9a, 0x0b},
+ {0x8a9b, 0x2b},
+ {0x8a9c, 0xe0},
+ {0x8a9d, 0xf5},
+ {0x8a9e, 0x19},
+ {0x8a9f, 0xe0},
+ {0x8aa0, 0xf5},
+ {0x8aa1, 0x1a},
+ {0x8aa2, 0x80},
+ {0x8aa3, 0x0f},
+ {0x8aa4, 0x12},
+ {0x8aa5, 0x0b},
+ {0x8aa6, 0x2b},
+ {0x8aa7, 0xe5},
+ {0x8aa8, 0x1d},
+ {0x8aa9, 0xf0},
+ {0x8aaa, 0x90},
+ {0x8aab, 0x0e},
+ {0x8aac, 0x5f},
+ {0x8aad, 0x12},
+ {0x8aae, 0x0b},
+ {0x8aaf, 0x2b},
+ {0x8ab0, 0xe5},
+ {0x8ab1, 0x1e},
+ {0x8ab2, 0xf0},
+ {0x8ab3, 0xa2},
+ {0x8ab4, 0x31},
+ {0x8ab5, 0x92},
+ {0x8ab6, 0xaf},
+ {0x8ab7, 0x22},
+ {0x8ab8, 0xd2},
+ {0x8ab9, 0x01},
+ {0x8aba, 0xc2},
+ {0x8abb, 0x02},
+ {0x8abc, 0xe4},
+ {0x8abd, 0xf5},
+ {0x8abe, 0x40},
+ {0x8abf, 0xf5},
+ {0x8ac0, 0x3f},
+ {0x8ac1, 0xd2},
+ {0x8ac2, 0x34},
+ {0x8ac3, 0xd2},
+ {0x8ac4, 0x32},
+ {0x8ac5, 0xd2},
+ {0x8ac6, 0x35},
+ {0x8ac7, 0xd2},
+ {0x8ac8, 0x01},
+ {0x8ac9, 0xc2},
+ {0x8aca, 0x02},
+ {0x8acb, 0xf5},
+ {0x8acc, 0x40},
+ {0x8acd, 0xf5},
+ {0x8ace, 0x3f},
+ {0x8acf, 0xd2},
+ {0x8ad0, 0x34},
+ {0x8ad1, 0xd2},
+ {0x8ad2, 0x32},
+ {0x8ad3, 0x22},
+ {0x8ad4, 0x8f},
+ {0x8ad5, 0x30},
+ {0x8ad6, 0x8e},
+ {0x8ad7, 0x2f},
+ {0x8ad8, 0x8d},
+ {0x8ad9, 0x2e},
+ {0x8ada, 0x8c},
+ {0x8adb, 0x2d},
+ {0x8adc, 0x22},
+ {0x8add, 0x12},
+ {0x8ade, 0x04},
+ {0x8adf, 0x47},
+ {0x8ae0, 0x8f},
+ {0x8ae1, 0x1e},
+ {0x8ae2, 0x8e},
+ {0x8ae3, 0x1d},
+ {0x8ae4, 0x8d},
+ {0x8ae5, 0x1c},
+ {0x8ae6, 0x8c},
+ {0x8ae7, 0x1b},
+ {0x8ae8, 0x22},
+ {0x8ae9, 0x93},
+ {0x8aea, 0xf9},
+ {0x8aeb, 0xf8},
+ {0x8aec, 0x02},
+ {0x8aed, 0x04},
+ {0x8aee, 0x34},
+ {0x8aef, 0x90},
+ {0x8af0, 0x0e},
+ {0x8af1, 0x81},
+ {0x8af2, 0x12},
+ {0x8af3, 0x04},
+ {0x8af4, 0x47},
+ {0x8af5, 0x8f},
+ {0x8af6, 0x3b},
+ {0x8af7, 0x8e},
+ {0x8af8, 0x3a},
+ {0x8af9, 0x8d},
+ {0x8afa, 0x39},
+ {0x8afb, 0x8c},
+ {0x8afc, 0x38},
+ {0x8afd, 0xd2},
+ {0x8afe, 0x06},
+ {0x8aff, 0x30},
+ {0x8b00, 0x06},
+ {0x8b01, 0x03},
+ {0x8b02, 0xd3},
+ {0x8b03, 0x80},
+ {0x8b04, 0x01},
+ {0x8b05, 0xc3},
+ {0x8b06, 0x92},
+ {0x8b07, 0x0e},
+ {0x8b08, 0x22},
+ {0x8b09, 0xc0},
+ {0x8b0a, 0xe0},
+ {0x8b0b, 0xc0},
+ {0x8b0c, 0x83},
+ {0x8b0d, 0xc0},
+ {0x8b0e, 0x82},
+ {0x8b0f, 0x90},
+ {0x8b10, 0x3f},
+ {0x8b11, 0x0d},
+ {0x8b12, 0xe0},
+ {0x8b13, 0xf5},
+ {0x8b14, 0x28},
+ {0x8b15, 0xe5},
+ {0x8b16, 0x28},
+ {0x8b17, 0xf0},
+ {0x8b18, 0xd0},
+ {0x8b19, 0x82},
+ {0x8b1a, 0xd0},
+ {0x8b1b, 0x83},
+ {0x8b1c, 0xd0},
+ {0x8b1d, 0xe0},
+ {0x8b1e, 0x32},
+ {0x8b1f, 0x78},
+ {0x8b20, 0x7f},
+ {0x8b21, 0xe4},
+ {0x8b22, 0xf6},
+ {0x8b23, 0xd8},
+ {0x8b24, 0xfd},
+ {0x8b25, 0x75},
+ {0x8b26, 0x81},
+ {0x8b27, 0xc0},
+ {0x8b28, 0x02},
+ {0x8b29, 0x09},
+ {0x8b2a, 0xa5},
+ {0x8b2b, 0xe4},
+ {0x8b2c, 0x93},
+ {0x8b2d, 0xfe},
+ {0x8b2e, 0x74},
+ {0x8b2f, 0x01},
+ {0x8b30, 0x93},
+ {0x8b31, 0xf5},
+ {0x8b32, 0x82},
+ {0x8b33, 0x8e},
+ {0x8b34, 0x83},
+ {0x8b35, 0x22},
+ {0x8b36, 0x8f},
+ {0x8b37, 0x82},
+ {0x8b38, 0x8e},
+ {0x8b39, 0x83},
+ {0x8b3a, 0x75},
+ {0x8b3b, 0xf0},
+ {0x8b3c, 0x04},
+ {0x8b3d, 0xed},
+ {0x8b3e, 0x02},
+ {0x8b3f, 0x04},
+ {0x8b40, 0x89},
+ {0x8b41, 0x00},
+ {0x8b42, 0x00},
+ {0x8b43, 0x00},
+ {0x8b44, 0x00},
+ {0x8b45, 0x00},
+ {0x8b46, 0x00},
+ {0x8b47, 0x00},
+ {0x8b48, 0x00},
+ {0x8b49, 0x00},
+ {0x8b4a, 0x00},
+ {0x8b4b, 0x00},
+ {0x8b4c, 0x00},
+ {0x8b4d, 0x00},
+ {0x8b4e, 0x00},
+ {0x8b4f, 0x00},
+ {0x8b50, 0x00},
+ {0x8b51, 0x00},
+ {0x8b52, 0x00},
+ {0x8b53, 0x00},
+ {0x8b54, 0x00},
+ {0x8b55, 0x00},
+ {0x8b56, 0x00},
+ {0x8b57, 0x00},
+ {0x8b58, 0x00},
+ {0x8b59, 0x00},
+ {0x8b5a, 0x00},
+ {0x8b5b, 0x00},
+ {0x8b5c, 0x00},
+ {0x8b5d, 0x00},
+ {0x8b5e, 0x00},
+ {0x8b5f, 0x00},
+ {0x8b60, 0x00},
+ {0x8b61, 0x00},
+ {0x8b62, 0x00},
+ {0x8b63, 0x00},
+ {0x8b64, 0x00},
+ {0x8b65, 0x00},
+ {0x8b66, 0x00},
+ {0x8b67, 0x00},
+ {0x8b68, 0x00},
+ {0x8b69, 0x00},
+ {0x8b6a, 0x00},
+ {0x8b6b, 0x00},
+ {0x8b6c, 0x00},
+ {0x8b6d, 0x00},
+ {0x8b6e, 0x00},
+ {0x8b6f, 0x00},
+ {0x8b70, 0x00},
+ {0x8b71, 0x00},
+ {0x8b72, 0x00},
+ {0x8b73, 0x00},
+ {0x8b74, 0x00},
+ {0x8b75, 0x00},
+ {0x8b76, 0x00},
+ {0x8b77, 0x00},
+ {0x8b78, 0x00},
+ {0x8b79, 0x00},
+ {0x8b7a, 0x00},
+ {0x8b7b, 0x00},
+ {0x8b7c, 0x00},
+ {0x8b7d, 0x00},
+ {0x8b7e, 0x00},
+ {0x8b7f, 0x00},
+ {0x8b80, 0x00},
+ {0x8b81, 0x00},
+ {0x8b82, 0x00},
+ {0x8b83, 0x00},
+ {0x8b84, 0x00},
+ {0x8b85, 0x00},
+ {0x8b86, 0x00},
+ {0x8b87, 0x00},
+ {0x8b88, 0x00},
+ {0x8b89, 0x00},
+ {0x8b8a, 0x00},
+ {0x8b8b, 0x00},
+ {0x8b8c, 0x00},
+ {0x8b8d, 0x00},
+ {0x8b8e, 0x00},
+ {0x8b8f, 0x00},
+ {0x8b90, 0x00},
+ {0x8b91, 0x00},
+ {0x8b92, 0x00},
+ {0x8b93, 0x00},
+ {0x8b94, 0x00},
+ {0x8b95, 0x00},
+ {0x8b96, 0x00},
+ {0x8b97, 0x00},
+ {0x8b98, 0x00},
+ {0x8b99, 0x00},
+ {0x8b9a, 0x00},
+ {0x8b9b, 0x00},
+ {0x8b9c, 0x00},
+ {0x8b9d, 0x00},
+ {0x8b9e, 0x00},
+ {0x8b9f, 0x00},
+ {0x8ba0, 0x00},
+ {0x8ba1, 0x00},
+ {0x8ba2, 0x00},
+ {0x8ba3, 0x00},
+ {0x8ba4, 0x00},
+ {0x8ba5, 0x00},
+ {0x8ba6, 0x00},
+ {0x8ba7, 0x00},
+ {0x8ba8, 0x00},
+ {0x8ba9, 0x00},
+ {0x8baa, 0x00},
+ {0x8bab, 0x00},
+ {0x8bac, 0x00},
+ {0x8bad, 0x00},
+ {0x8bae, 0x00},
+ {0x8baf, 0x00},
+ {0x8bb0, 0x00},
+ {0x8bb1, 0x00},
+ {0x8bb2, 0x00},
+ {0x8bb3, 0x00},
+ {0x8bb4, 0x00},
+ {0x8bb5, 0x00},
+ {0x8bb6, 0x00},
+ {0x8bb7, 0x00},
+ {0x8bb8, 0x00},
+ {0x8bb9, 0x00},
+ {0x8bba, 0x00},
+ {0x8bbb, 0x00},
+ {0x8bbc, 0x00},
+ {0x8bbd, 0x00},
+ {0x8bbe, 0x00},
+ {0x8bbf, 0x00},
+ {0x8bc0, 0x00},
+ {0x8bc1, 0x00},
+ {0x8bc2, 0x00},
+ {0x8bc3, 0x00},
+ {0x8bc4, 0x00},
+ {0x8bc5, 0x00},
+ {0x8bc6, 0x00},
+ {0x8bc7, 0x00},
+ {0x8bc8, 0x00},
+ {0x8bc9, 0x00},
+ {0x8bca, 0x00},
+ {0x8bcb, 0x00},
+ {0x8bcc, 0x00},
+ {0x8bcd, 0x00},
+ {0x8bce, 0x00},
+ {0x8bcf, 0x00},
+ {0x8bd0, 0x00},
+ {0x8bd1, 0x00},
+ {0x8bd2, 0x00},
+ {0x8bd3, 0x00},
+ {0x8bd4, 0x00},
+ {0x8bd5, 0x00},
+ {0x8bd6, 0x00},
+ {0x8bd7, 0x00},
+ {0x8bd8, 0x00},
+ {0x8bd9, 0x00},
+ {0x8bda, 0x00},
+ {0x8bdb, 0x00},
+ {0x8bdc, 0x00},
+ {0x8bdd, 0x00},
+ {0x8bde, 0x00},
+ {0x8bdf, 0x00},
+ {0x8be0, 0x00},
+ {0x8be1, 0x00},
+ {0x8be2, 0x00},
+ {0x8be3, 0x00},
+ {0x8be4, 0x00},
+ {0x8be5, 0x00},
+ {0x8be6, 0x00},
+ {0x8be7, 0x00},
+ {0x8be8, 0x00},
+ {0x8be9, 0x00},
+ {0x8bea, 0x00},
+ {0x8beb, 0x00},
+ {0x8bec, 0x00},
+ {0x8bed, 0x00},
+ {0x8bee, 0x00},
+ {0x8bef, 0x00},
+ {0x8bf0, 0x00},
+ {0x8bf1, 0x00},
+ {0x8bf2, 0x00},
+ {0x8bf3, 0x00},
+ {0x8bf4, 0x00},
+ {0x8bf5, 0x00},
+ {0x8bf6, 0x00},
+ {0x8bf7, 0x00},
+ {0x8bf8, 0x00},
+ {0x8bf9, 0x00},
+ {0x8bfa, 0x00},
+ {0x8bfb, 0x00},
+ {0x8bfc, 0x00},
+ {0x8bfd, 0x00},
+ {0x8bfe, 0x00},
+ {0x8bff, 0x00},
+ {0x8c00, 0x00},
+ {0x8c01, 0x00},
+ {0x8c02, 0x00},
+ {0x8c03, 0x00},
+ {0x8c04, 0x00},
+ {0x8c05, 0x00},
+ {0x8c06, 0x00},
+ {0x8c07, 0x00},
+ {0x8c08, 0x00},
+ {0x8c09, 0x00},
+ {0x8c0a, 0x00},
+ {0x8c0b, 0x00},
+ {0x8c0c, 0x00},
+ {0x8c0d, 0x00},
+ {0x8c0e, 0x00},
+ {0x8c0f, 0x00},
+ {0x8c10, 0x00},
+ {0x8c11, 0x00},
+ {0x8c12, 0x00},
+ {0x8c13, 0x00},
+ {0x8c14, 0x00},
+ {0x8c15, 0x00},
+ {0x8c16, 0x00},
+ {0x8c17, 0x00},
+ {0x8c18, 0x00},
+ {0x8c19, 0x00},
+ {0x8c1a, 0x00},
+ {0x8c1b, 0x00},
+ {0x8c1c, 0x00},
+ {0x8c1d, 0x00},
+ {0x8c1e, 0x00},
+ {0x8c1f, 0x00},
+ {0x8c20, 0x00},
+ {0x8c21, 0x00},
+ {0x8c22, 0x00},
+ {0x8c23, 0x00},
+ {0x8c24, 0x00},
+ {0x8c25, 0x00},
+ {0x8c26, 0x00},
+ {0x8c27, 0x00},
+ {0x8c28, 0x00},
+ {0x8c29, 0x00},
+ {0x8c2a, 0x00},
+ {0x8c2b, 0x00},
+ {0x8c2c, 0x00},
+ {0x8c2d, 0x00},
+ {0x8c2e, 0x00},
+ {0x8c2f, 0x00},
+ {0x8c30, 0x00},
+ {0x8c31, 0x00},
+ {0x8c32, 0x00},
+ {0x8c33, 0x00},
+ {0x8c34, 0x00},
+ {0x8c35, 0x00},
+ {0x8c36, 0x00},
+ {0x8c37, 0x00},
+ {0x8c38, 0x00},
+ {0x8c39, 0x00},
+ {0x8c3a, 0x00},
+ {0x8c3b, 0x00},
+ {0x8c3c, 0x00},
+ {0x8c3d, 0x00},
+ {0x8c3e, 0x00},
+ {0x8c3f, 0x00},
+ {0x8c40, 0x00},
+ {0x8c41, 0x00},
+ {0x8c42, 0x00},
+ {0x8c43, 0x00},
+ {0x8c44, 0x00},
+ {0x8c45, 0x00},
+ {0x8c46, 0x00},
+ {0x8c47, 0x00},
+ {0x8c48, 0x00},
+ {0x8c49, 0x00},
+ {0x8c4a, 0x00},
+ {0x8c4b, 0x00},
+ {0x8c4c, 0x00},
+ {0x8c4d, 0x00},
+ {0x8c4e, 0x00},
+ {0x8c4f, 0x00},
+ {0x8c50, 0x00},
+ {0x8c51, 0x00},
+ {0x8c52, 0x00},
+ {0x8c53, 0x00},
+ {0x8c54, 0x00},
+ {0x8c55, 0x00},
+ {0x8c56, 0x00},
+ {0x8c57, 0x00},
+ {0x8c58, 0x00},
+ {0x8c59, 0x00},
+ {0x8c5a, 0x00},
+ {0x8c5b, 0x00},
+ {0x8c5c, 0x00},
+ {0x8c5d, 0x00},
+ {0x8c5e, 0x00},
+ {0x8c5f, 0x00},
+ {0x8c60, 0x00},
+ {0x8c61, 0x00},
+ {0x8c62, 0x00},
+ {0x8c63, 0x00},
+ {0x8c64, 0x00},
+ {0x8c65, 0x00},
+ {0x8c66, 0x00},
+ {0x8c67, 0x00},
+ {0x8c68, 0x00},
+ {0x8c69, 0x00},
+ {0x8c6a, 0x00},
+ {0x8c6b, 0x00},
+ {0x8c6c, 0x00},
+ {0x8c6d, 0x00},
+ {0x8c6e, 0x00},
+ {0x8c6f, 0x00},
+ {0x8c70, 0x00},
+ {0x8c71, 0x00},
+ {0x8c72, 0x00},
+ {0x8c73, 0x00},
+ {0x8c74, 0x00},
+ {0x8c75, 0x00},
+ {0x8c76, 0x00},
+ {0x8c77, 0x00},
+ {0x8c78, 0x00},
+ {0x8c79, 0x00},
+ {0x8c7a, 0x00},
+ {0x8c7b, 0x00},
+ {0x8c7c, 0x00},
+ {0x8c7d, 0x00},
+ {0x8c7e, 0x00},
+ {0x8c7f, 0x00},
+ {0x8c80, 0x00},
+ {0x8c81, 0x00},
+ {0x8c82, 0x00},
+ {0x8c83, 0x00},
+ {0x8c84, 0x00},
+ {0x8c85, 0x00},
+ {0x8c86, 0x00},
+ {0x8c87, 0x00},
+ {0x8c88, 0x00},
+ {0x8c89, 0x00},
+ {0x8c8a, 0x00},
+ {0x8c8b, 0x00},
+ {0x8c8c, 0x00},
+ {0x8c8d, 0x00},
+ {0x8c8e, 0x00},
+ {0x8c8f, 0x00},
+ {0x8c90, 0x00},
+ {0x8c91, 0x00},
+ {0x8c92, 0x00},
+ {0x8c93, 0x00},
+ {0x8c94, 0x00},
+ {0x8c95, 0x00},
+ {0x8c96, 0x00},
+ {0x8c97, 0x00},
+ {0x8c98, 0x00},
+ {0x8c99, 0x00},
+ {0x8c9a, 0x00},
+ {0x8c9b, 0x00},
+ {0x8c9c, 0x00},
+ {0x8c9d, 0x00},
+ {0x8c9e, 0x00},
+ {0x8c9f, 0x00},
+ {0x8ca0, 0x00},
+ {0x8ca1, 0x00},
+ {0x8ca2, 0x00},
+ {0x8ca3, 0x00},
+ {0x8ca4, 0x00},
+ {0x8ca5, 0x00},
+ {0x8ca6, 0x00},
+ {0x8ca7, 0x00},
+ {0x8ca8, 0x00},
+ {0x8ca9, 0x00},
+ {0x8caa, 0x00},
+ {0x8cab, 0x00},
+ {0x8cac, 0x00},
+ {0x8cad, 0x00},
+ {0x8cae, 0x00},
+ {0x8caf, 0x00},
+ {0x8cb0, 0x00},
+ {0x8cb1, 0x00},
+ {0x8cb2, 0x00},
+ {0x8cb3, 0x00},
+ {0x8cb4, 0x00},
+ {0x8cb5, 0x00},
+ {0x8cb6, 0x00},
+ {0x8cb7, 0x00},
+ {0x8cb8, 0x00},
+ {0x8cb9, 0x00},
+ {0x8cba, 0x00},
+ {0x8cbb, 0x00},
+ {0x8cbc, 0x00},
+ {0x8cbd, 0x00},
+ {0x8cbe, 0x00},
+ {0x8cbf, 0x00},
+ {0x8cc0, 0x00},
+ {0x8cc1, 0x00},
+ {0x8cc2, 0x00},
+ {0x8cc3, 0x00},
+ {0x8cc4, 0x00},
+ {0x8cc5, 0x00},
+ {0x8cc6, 0x00},
+ {0x8cc7, 0x00},
+ {0x8cc8, 0x00},
+ {0x8cc9, 0x00},
+ {0x8cca, 0x00},
+ {0x8ccb, 0x00},
+ {0x8ccc, 0x00},
+ {0x8ccd, 0x00},
+ {0x8cce, 0x00},
+ {0x8ccf, 0x00},
+ {0x8cd0, 0x00},
+ {0x8cd1, 0x00},
+ {0x8cd2, 0x00},
+ {0x8cd3, 0x00},
+ {0x8cd4, 0x00},
+ {0x8cd5, 0x00},
+ {0x8cd6, 0x00},
+ {0x8cd7, 0x00},
+ {0x8cd8, 0x00},
+ {0x8cd9, 0x00},
+ {0x8cda, 0x00},
+ {0x8cdb, 0x00},
+ {0x8cdc, 0x00},
+ {0x8cdd, 0x00},
+ {0x8cde, 0x00},
+ {0x8cdf, 0x00},
+ {0x8ce0, 0x00},
+ {0x8ce1, 0x00},
+ {0x8ce2, 0x00},
+ {0x8ce3, 0x00},
+ {0x8ce4, 0x00},
+ {0x8ce5, 0x00},
+ {0x8ce6, 0x00},
+ {0x8ce7, 0x00},
+ {0x8ce8, 0x00},
+ {0x8ce9, 0x00},
+ {0x8cea, 0x00},
+ {0x8ceb, 0x00},
+ {0x8cec, 0x00},
+ {0x8ced, 0x00},
+ {0x8cee, 0x00},
+ {0x8cef, 0x00},
+ {0x8cf0, 0x00},
+ {0x8cf1, 0x00},
+ {0x8cf2, 0x00},
+ {0x8cf3, 0x00},
+ {0x8cf4, 0x00},
+ {0x8cf5, 0x00},
+ {0x8cf6, 0x00},
+ {0x8cf7, 0x00},
+ {0x8cf8, 0x00},
+ {0x8cf9, 0x00},
+ {0x8cfa, 0x00},
+ {0x8cfb, 0x00},
+ {0x8cfc, 0x00},
+ {0x8cfd, 0x00},
+ {0x8cfe, 0x00},
+ {0x8cff, 0x00},
+ {0x8d00, 0x00},
+ {0x8d01, 0x00},
+ {0x8d02, 0x00},
+ {0x8d03, 0x00},
+ {0x8d04, 0x00},
+ {0x8d05, 0x00},
+ {0x8d06, 0x00},
+ {0x8d07, 0x00},
+ {0x8d08, 0x00},
+ {0x8d09, 0x00},
+ {0x8d0a, 0x00},
+ {0x8d0b, 0x00},
+ {0x8d0c, 0x00},
+ {0x8d0d, 0x00},
+ {0x8d0e, 0x00},
+ {0x8d0f, 0x00},
+ {0x8d10, 0x00},
+ {0x8d11, 0x00},
+ {0x8d12, 0x00},
+ {0x8d13, 0x00},
+ {0x8d14, 0x00},
+ {0x8d15, 0x00},
+ {0x8d16, 0x00},
+ {0x8d17, 0x00},
+ {0x8d18, 0x00},
+ {0x8d19, 0x00},
+ {0x8d1a, 0x00},
+ {0x8d1b, 0x00},
+ {0x8d1c, 0x00},
+ {0x8d1d, 0x00},
+ {0x8d1e, 0x00},
+ {0x8d1f, 0x00},
+ {0x8d20, 0x00},
+ {0x8d21, 0x00},
+ {0x8d22, 0x00},
+ {0x8d23, 0x00},
+ {0x8d24, 0x00},
+ {0x8d25, 0x00},
+ {0x8d26, 0x00},
+ {0x8d27, 0x00},
+ {0x8d28, 0x00},
+ {0x8d29, 0x00},
+ {0x8d2a, 0x00},
+ {0x8d2b, 0x00},
+ {0x8d2c, 0x00},
+ {0x8d2d, 0x00},
+ {0x8d2e, 0x00},
+ {0x8d2f, 0x00},
+ {0x8d30, 0x00},
+ {0x8d31, 0x00},
+ {0x8d32, 0x00},
+ {0x8d33, 0x00},
+ {0x8d34, 0x00},
+ {0x8d35, 0x00},
+ {0x8d36, 0x00},
+ {0x8d37, 0x00},
+ {0x8d38, 0x00},
+ {0x8d39, 0x00},
+ {0x8d3a, 0x00},
+ {0x8d3b, 0x00},
+ {0x8d3c, 0x00},
+ {0x8d3d, 0x00},
+ {0x8d3e, 0x00},
+ {0x8d3f, 0x00},
+ {0x8d40, 0x00},
+ {0x8d41, 0x00},
+ {0x8d42, 0x00},
+ {0x8d43, 0x00},
+ {0x8d44, 0x00},
+ {0x8d45, 0x00},
+ {0x8d46, 0x00},
+ {0x8d47, 0x00},
+ {0x8d48, 0x00},
+ {0x8d49, 0x00},
+ {0x8d4a, 0x00},
+ {0x8d4b, 0x00},
+ {0x8d4c, 0x00},
+ {0x8d4d, 0x00},
+ {0x8d4e, 0x00},
+ {0x8d4f, 0x00},
+ {0x8d50, 0x00},
+ {0x8d51, 0x00},
+ {0x8d52, 0x00},
+ {0x8d53, 0x00},
+ {0x8d54, 0x00},
+ {0x8d55, 0x00},
+ {0x8d56, 0x00},
+ {0x8d57, 0x00},
+ {0x8d58, 0x00},
+ {0x8d59, 0x00},
+ {0x8d5a, 0x00},
+ {0x8d5b, 0x00},
+ {0x8d5c, 0x00},
+ {0x8d5d, 0x00},
+ {0x8d5e, 0x00},
+ {0x8d5f, 0x00},
+ {0x8d60, 0x00},
+ {0x8d61, 0x00},
+ {0x8d62, 0x00},
+ {0x8d63, 0x00},
+ {0x8d64, 0x00},
+ {0x8d65, 0x00},
+ {0x8d66, 0x00},
+ {0x8d67, 0x00},
+ {0x8d68, 0x00},
+ {0x8d69, 0x00},
+ {0x8d6a, 0x00},
+ {0x8d6b, 0x00},
+ {0x8d6c, 0x00},
+ {0x8d6d, 0x00},
+ {0x8d6e, 0x00},
+ {0x8d6f, 0x00},
+ {0x8d70, 0x00},
+ {0x8d71, 0x00},
+ {0x8d72, 0x00},
+ {0x8d73, 0x00},
+ {0x8d74, 0x00},
+ {0x8d75, 0x00},
+ {0x8d76, 0x00},
+ {0x8d77, 0x00},
+ {0x8d78, 0x00},
+ {0x8d79, 0x00},
+ {0x8d7a, 0x00},
+ {0x8d7b, 0x00},
+ {0x8d7c, 0x00},
+ {0x8d7d, 0x00},
+ {0x8d7e, 0x00},
+ {0x8d7f, 0x00},
+ {0x8d80, 0x00},
+ {0x8d81, 0x00},
+ {0x8d82, 0x00},
+ {0x8d83, 0x00},
+ {0x8d84, 0x00},
+ {0x8d85, 0x00},
+ {0x8d86, 0x00},
+ {0x8d87, 0x00},
+ {0x8d88, 0x00},
+ {0x8d89, 0x00},
+ {0x8d8a, 0x00},
+ {0x8d8b, 0x00},
+ {0x8d8c, 0x00},
+ {0x8d8d, 0x00},
+ {0x8d8e, 0x00},
+ {0x8d8f, 0x00},
+ {0x8d90, 0x00},
+ {0x8d91, 0x00},
+ {0x8d92, 0x00},
+ {0x8d93, 0x00},
+ {0x8d94, 0x00},
+ {0x8d95, 0x00},
+ {0x8d96, 0x00},
+ {0x8d97, 0x00},
+ {0x8d98, 0x00},
+ {0x8d99, 0x00},
+ {0x8d9a, 0x00},
+ {0x8d9b, 0x00},
+ {0x8d9c, 0x00},
+ {0x8d9d, 0x00},
+ {0x8d9e, 0x00},
+ {0x8d9f, 0x00},
+ {0x8da0, 0x00},
+ {0x8da1, 0x00},
+ {0x8da2, 0x00},
+ {0x8da3, 0x00},
+ {0x8da4, 0x00},
+ {0x8da5, 0x00},
+ {0x8da6, 0x00},
+ {0x8da7, 0x00},
+ {0x8da8, 0x00},
+ {0x8da9, 0x00},
+ {0x8daa, 0x00},
+ {0x8dab, 0x00},
+ {0x8dac, 0x00},
+ {0x8dad, 0x00},
+ {0x8dae, 0x00},
+ {0x8daf, 0x00},
+ {0x8db0, 0x00},
+ {0x8db1, 0x00},
+ {0x8db2, 0x00},
+ {0x8db3, 0x00},
+ {0x8db4, 0x00},
+ {0x8db5, 0x00},
+ {0x8db6, 0x00},
+ {0x8db7, 0x00},
+ {0x8db8, 0x00},
+ {0x8db9, 0x00},
+ {0x8dba, 0x00},
+ {0x8dbb, 0x00},
+ {0x8dbc, 0x00},
+ {0x8dbd, 0x00},
+ {0x8dbe, 0x00},
+ {0x8dbf, 0x00},
+ {0x8dc0, 0x00},
+ {0x8dc1, 0x00},
+ {0x8dc2, 0x00},
+ {0x8dc3, 0x00},
+ {0x8dc4, 0x00},
+ {0x8dc5, 0x00},
+ {0x8dc6, 0x00},
+ {0x8dc7, 0x00},
+ {0x8dc8, 0x00},
+ {0x8dc9, 0x00},
+ {0x8dca, 0x00},
+ {0x8dcb, 0x00},
+ {0x8dcc, 0x00},
+ {0x8dcd, 0x00},
+ {0x8dce, 0x00},
+ {0x8dcf, 0x00},
+ {0x8dd0, 0x00},
+ {0x8dd1, 0x00},
+ {0x8dd2, 0x00},
+ {0x8dd3, 0x00},
+ {0x8dd4, 0x00},
+ {0x8dd5, 0x00},
+ {0x8dd6, 0x00},
+ {0x8dd7, 0x00},
+ {0x8dd8, 0x00},
+ {0x8dd9, 0x00},
+ {0x8dda, 0x00},
+ {0x8ddb, 0x00},
+ {0x8ddc, 0x00},
+ {0x8ddd, 0x00},
+ {0x8dde, 0x00},
+ {0x8ddf, 0x00},
+ {0x8de0, 0x00},
+ {0x8de1, 0x00},
+ {0x8de2, 0x00},
+ {0x8de3, 0x00},
+ {0x8de4, 0x00},
+ {0x8de5, 0x00},
+ {0x8de6, 0x00},
+ {0x8de7, 0x00},
+ {0x8de8, 0x00},
+ {0x8de9, 0x00},
+ {0x8dea, 0x00},
+ {0x8deb, 0x00},
+ {0x8dec, 0x00},
+ {0x8ded, 0x00},
+ {0x8dee, 0x00},
+ {0x8def, 0x00},
+ {0x8df0, 0x00},
+ {0x8df1, 0x00},
+ {0x8df2, 0x00},
+ {0x8df3, 0x00},
+ {0x8df4, 0x00},
+ {0x8df5, 0x00},
+ {0x8df6, 0x00},
+ {0x8df7, 0x00},
+ {0x8df8, 0x00},
+ {0x8df9, 0x00},
+ {0x8dfa, 0x00},
+ {0x8dfb, 0x00},
+ {0x8dfc, 0x00},
+ {0x8dfd, 0x00},
+ {0x8dfe, 0x00},
+ {0x8dff, 0x00},
+ {0x8e00, 0x11},
+ {0x8e01, 0x02},
+ {0x8e02, 0x28},
+ {0x8e03, 0x09},
+ {0x8e04, 0x00},
+ {0x8e05, 0x12},
+ {0x8e06, 0x4f},
+ {0x8e07, 0x56},
+ {0x8e08, 0x54},
+ {0x8e09, 0x20},
+ {0x8e0a, 0x20},
+ {0x8e0b, 0x20},
+ {0x8e0c, 0x20},
+ {0x8e0d, 0x20},
+ {0x8e0e, 0x20},
+ {0x8e0f, 0x01},
+ {0x8e10, 0x10},
+ {0x8e11, 0x00},
+ {0x8e12, 0x56},
+ {0x8e13, 0x40},
+ {0x8e14, 0x1a},
+ {0x8e15, 0x30},
+ {0x8e16, 0x29},
+ {0x8e17, 0x7e},
+ {0x8e18, 0x00},
+ {0x8e19, 0x30},
+ {0x8e1a, 0x04},
+ {0x8e1b, 0x20},
+ {0x8e1c, 0xdf},
+ {0x8e1d, 0x30},
+ {0x8e1e, 0x05},
+ {0x8e1f, 0x40},
+ {0x8e20, 0xbf},
+ {0x8e21, 0x50},
+ {0x8e22, 0x25},
+ {0x8e23, 0x04},
+ {0x8e24, 0xfb},
+ {0x8e25, 0x50},
+ {0x8e26, 0x03},
+ {0x8e27, 0x00},
+ {0x8e28, 0xfd},
+ {0x8e29, 0x50},
+ {0x8e2a, 0x27},
+ {0x8e2b, 0x01},
+ {0x8e2c, 0xfe},
+ {0x8e2d, 0x60},
+ {0x8e2e, 0x00},
+ {0x8e2f, 0x11},
+ {0x8e30, 0x00},
+ {0x8e31, 0x3f},
+ {0x8e32, 0x05},
+ {0x8e33, 0x30},
+ {0x8e34, 0x00},
+ {0x8e35, 0x3f},
+ {0x8e36, 0x06},
+ {0x8e37, 0x22},
+ {0x8e38, 0x00},
+ {0x8e39, 0x3f},
+ {0x8e3a, 0x01},
+ {0x8e3b, 0x29},
+ {0x8e3c, 0x00},
+ {0x8e3d, 0x3f},
+ {0x8e3e, 0x02},
+ {0x8e3f, 0x00},
+ {0x8e40, 0x00},
+ {0x8e41, 0x36},
+ {0x8e42, 0x06},
+ {0x8e43, 0x07},
+ {0x8e44, 0x00},
+ {0x8e45, 0x3f},
+ {0x8e46, 0x0b},
+ {0x8e47, 0x0f},
+ {0x8e48, 0xf0},
+ {0x8e49, 0x30},
+ {0x8e4a, 0x01},
+ {0x8e4b, 0x40},
+ {0x8e4c, 0xbf},
+ {0x8e4d, 0x30},
+ {0x8e4e, 0x01},
+ {0x8e4f, 0x00},
+ {0x8e50, 0xbf},
+ {0x8e51, 0x30},
+ {0x8e52, 0x29},
+ {0x8e53, 0x70},
+ {0x8e54, 0x00},
+ {0x8e55, 0x3a},
+ {0x8e56, 0x00},
+ {0x8e57, 0x01},
+ {0x8e58, 0xfe},
+ {0x8e59, 0x3a},
+ {0x8e5a, 0x00},
+ {0x8e5b, 0x00},
+ {0x8e5c, 0xfe},
+ {0x8e5d, 0x36},
+ {0x8e5e, 0x03},
+ {0x8e5f, 0x36},
+ {0x8e60, 0x02},
+ {0x8e61, 0x41},
+ {0x8e62, 0x44},
+ {0x8e63, 0x58},
+ {0x8e64, 0x20},
+ {0x8e65, 0x18},
+ {0x8e66, 0x10},
+ {0x8e67, 0x0a},
+ {0x8e68, 0x04},
+ {0x8e69, 0x04},
+ {0x8e6a, 0x00},
+ {0x8e6b, 0x03},
+ {0x8e6c, 0xff},
+ {0x8e6d, 0x64},
+ {0x8e6e, 0x00},
+ {0x8e6f, 0x00},
+ {0x8e70, 0x80},
+ {0x8e71, 0x00},
+ {0x8e72, 0x00},
+ {0x8e73, 0x00},
+ {0x8e74, 0x00},
+ {0x8e75, 0x00},
+ {0x8e76, 0x00},
+ {0x8e77, 0x02},
+ {0x8e78, 0x04},
+ {0x8e79, 0x06},
+ {0x8e7a, 0x00},
+ {0x8e7b, 0x03},
+ {0x8e7c, 0x98},
+ {0x8e7d, 0x00},
+ {0x8e7e, 0xcc},
+ {0x8e7f, 0x50},
+ {0x8e80, 0x3c},
+ {0x8e81, 0x28},
+ {0x8e82, 0x1e},
+ {0x8e83, 0x0c},
+ {0x8e84, 0x0c},
+ {0x8e85, 0x00},
+ {0x8e86, 0x00},
+ {0x8e87, 0x00},
+ {0x8e88, 0x6e},
+ {0x8e89, 0x05},
+ {0x8e8a, 0x05},
+ {0x8e8b, 0x00},
+ {0x8e8c, 0xa5},
+ {0x8e8d, 0x5a},
+ {0x3022, 0x00},
+ {0x3023, 0x00},
+ {0x3024, 0x00},
+ {0x3025, 0x00},
+ {0x3026, 0x00},
+ {0x3027, 0x00},
+ {0x3028, 0x00},
+ {0x3029, 0xFF},
+ {0x3000, 0x00},
+ {OV5640_TABLE_END, 0x0000}
+};
+
+static struct ov5640_reg tbl_single_focus[] = {
+ {0x3023, 0x01},
+ {0x3022, 0x03},
+ {OV5640_TABLE_END, 0x0000}
+};
+
+static struct ov5640_reg tbl_release_focus[] = {
+ {0x3023, 0x01},
+ {0x3022, 0x08},
+ {OV5640_TABLE_END, 0x0000}
+};
+
+#endif
diff --git a/drivers/media/video/tegra/ov5650.c b/drivers/media/video/tegra/ov5650.c
index a8436210561a..bac1d00c3bd0 100644
--- a/drivers/media/video/tegra/ov5650.c
+++ b/drivers/media/video/tegra/ov5650.c
@@ -39,6 +39,11 @@ struct ov5650_info {
enum StereoCameraMode camera_mode;
struct ov5650_sensor left;
struct ov5650_sensor right;
+ struct ov5650_sensordata sensor_data;
+ struct mutex mutex_le;
+ struct mutex mutex_ri;
+ int power_refcnt_le;
+ int power_refcnt_ri;
u8 i2c_trans_buf[SIZEOF_I2C_TRANSBUF];
};
@@ -118,7 +123,7 @@ static struct ov5650_reg mode_start[] = {
{0x4000, 0x01},
{0x401c, 0x48},
{0x401d, 0x08},
- {0x5000, 0x00},
+ {0x5000, 0x06},
{0x5001, 0x00},
{0x5002, 0x00},
{0x503d, 0x00},
@@ -291,7 +296,6 @@ static struct ov5650_reg mode_2080x1164[] = {
{0x401d, 0x08},
{0x4001, 0x02},
- {0x5000, 0x00},
{0x5001, 0x00},
{0x5002, 0x00},
{0x503d, 0x00},
@@ -414,7 +418,6 @@ static struct ov5650_reg mode_1920x1080[] = {
{0x401d, 0x08},
{0x4001, 0x02},
- {0x5000, 0x00},
{0x5001, 0x00},
{0x5002, 0x00},
{0x503d, 0x00},
@@ -664,7 +667,6 @@ static struct ov5650_reg mode_320x240[] = {
{0x3810, 0x40},
{0x3836, 0x41},
{0x505f, 0x04},
- {0x5000, 0x06},
{0x5001, 0x00},
{0x5002, 0x02},
{0x503d, 0x00},
@@ -788,7 +790,7 @@ static int ov5650_read_reg(struct i2c_client *client, u16 addr, u8 *val)
err = i2c_transfer(client->adapter, msg, 2);
- if (err != 1)
+ if (err != 2)
return -EINVAL;
*val = data[2];
@@ -1245,31 +1247,71 @@ static int ov5650_test_pattern(struct ov5650_info *info,
}
static int set_power_helper(struct ov5650_platform_data *pdata,
- int powerLevel)
+ int powerLevel, int *ref_cnt)
{
if (pdata) {
- if (powerLevel && pdata->power_on)
- pdata->power_on();
- else if (pdata->power_off)
- pdata->power_off();
+ if (powerLevel && pdata->power_on) {
+ if (*ref_cnt == 0)
+ pdata->power_on();
+ *ref_cnt = *ref_cnt + 1;
+ }
+ else if (pdata->power_off) {
+ *ref_cnt = *ref_cnt - 1;
+ if (*ref_cnt <= 0)
+ pdata->power_off();
+ }
}
return 0;
}
-static int ov5650_set_power(int powerLevel)
+static int ov5650_set_power(struct ov5650_info *info, int powerLevel)
{
pr_info("%s: powerLevel=%d camera mode=%d\n", __func__, powerLevel,
- stereo_ov5650_info->camera_mode);
+ info->camera_mode);
- if (StereoCameraMode_Left & stereo_ov5650_info->camera_mode)
- set_power_helper(stereo_ov5650_info->left.pdata, powerLevel);
+ if (StereoCameraMode_Left & info->camera_mode) {
+ mutex_lock(&info->mutex_le);
+ set_power_helper(info->left.pdata, powerLevel,
+ &info->power_refcnt_le);
+ mutex_unlock(&info->mutex_le);
+ }
- if (StereoCameraMode_Right & stereo_ov5650_info->camera_mode)
- set_power_helper(stereo_ov5650_info->right.pdata, powerLevel);
+ if (StereoCameraMode_Right & info->camera_mode) {
+ mutex_lock(&info->mutex_ri);
+ set_power_helper(info->right.pdata, powerLevel,
+ &info->power_refcnt_ri);
+ mutex_unlock(&info->mutex_ri);
+ }
return 0;
}
+static int ov5650_get_sensor_id(struct ov5650_info *info)
+{
+ int ret = 0;
+ int i;
+ u8 bak;
+
+ pr_info("%s\n", __func__);
+ if (info->sensor_data.fuse_id_size)
+ return 0;
+
+ ov5650_set_power(info, 1);
+
+ for (i = 0; i < 5; i++) {
+ ret |= ov5650_write_reg_helper(info, 0x3d00, i);
+ ret |= ov5650_read_reg_helper(info, 0x3d04,
+ &bak);
+ info->sensor_data.fuse_id[i] = bak;
+ }
+
+ if (!ret)
+ info->sensor_data.fuse_id_size = i;
+
+ ov5650_set_power(info, 0);
+ return ret;
+}
+
static long ov5650_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
@@ -1280,13 +1322,13 @@ static long ov5650_ioctl(struct file *file,
case OV5650_IOCTL_SET_CAMERA_MODE:
{
if (info->camera_mode != arg) {
- err = ov5650_set_power(0);
+ err = ov5650_set_power(info, 0);
if (err) {
pr_info("%s %d\n", __func__, __LINE__);
return err;
}
info->camera_mode = arg;
- err = ov5650_set_power(1);
+ err = ov5650_set_power(info, 1);
if (err)
return err;
}
@@ -1344,6 +1386,21 @@ static long ov5650_ioctl(struct file *file,
}
return ov5650_set_group_hold(info, &ae);
}
+ case OV5650_IOCTL_GET_SENSORDATA:
+ {
+ err = ov5650_get_sensor_id(info);
+ if (err) {
+ pr_err("%s %d %d\n", __func__, __LINE__, err);
+ return err;
+ }
+ if (copy_to_user((void __user *)arg,
+ &info->sensor_data,
+ sizeof(struct ov5650_sensordata))) {
+ pr_info("%s %d\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+ return 0;
+ }
default:
return -EINVAL;
}
@@ -1354,13 +1411,15 @@ static int ov5650_open(struct inode *inode, struct file *file)
{
pr_info("%s\n", __func__);
file->private_data = stereo_ov5650_info;
- ov5650_set_power(1);
+ ov5650_set_power(stereo_ov5650_info, 1);
return 0;
}
int ov5650_release(struct inode *inode, struct file *file)
{
- ov5650_set_power(0);
+ struct ov5650_info *info = file->private_data;
+
+ ov5650_set_power(info, 0);
file->private_data = NULL;
return 0;
}
@@ -1426,6 +1485,8 @@ static int left_ov5650_probe(struct i2c_client *client,
stereo_ov5650_info->left.pdata = client->dev.platform_data;
stereo_ov5650_info->left.i2c_client = client;
+ mutex_init(&stereo_ov5650_info->mutex_le);
+ mutex_init(&stereo_ov5650_info->mutex_ri);
return 0;
}
diff --git a/drivers/media/video/tegra/sh532u.c b/drivers/media/video/tegra/sh532u.c
index 014b4bd30ca9..84692d992154 100644
--- a/drivers/media/video/tegra/sh532u.c
+++ b/drivers/media/video/tegra/sh532u.c
@@ -113,7 +113,9 @@
#define SH532U_TIMEOUT_MS 200
#define SH532U_POS_LOW_DEFAULT 0xA000
#define SH532U_POS_HIGH_DEFAULT 0x6000
-
+#define SH532U_SLEW_RATE 1
+#define SH532U_POS_TRANSLATE 0
+#define SH532U_POS_SIGN_CHANGER (-1)
static u8 sh532u_ids[] = {
0xF0,
@@ -148,6 +150,7 @@ struct sh532u_info {
unsigned i2c_addr_rom;
struct nvc_focus_nvc nvc;
struct nvc_focus_cap cap;
+ struct nv_focuser_config config;
enum nvc_focus_sts sts;
struct sh532u_pdata_info cfg;
bool reset_flag;
@@ -172,6 +175,8 @@ static struct nvc_focus_cap sh532u_default_cap = {
.focus_macro = SH532U_FOCUS_MACRO,
.focus_hyper = SH532U_FOCUS_HYPER,
.focus_infinity = SH532U_FOCUS_INFINITY,
+ .slew_rate = SH532U_SLEW_RATE,
+ .position_translate = SH532U_POS_TRANSLATE,
};
static struct nvc_focus_nvc sh532u_default_nvc = {
@@ -532,7 +537,7 @@ static int sh532u_vreg_init(struct sh532u_info *info)
else
dev_info(&info->i2c_client->dev,
"%s no regulator found for %s. "
- "This board may not have an"
+ "This board may not have an "
"independent %s regulator.\n",
__func__, info->vreg[j].vreg_name,
info->vreg[j].vreg_name);
@@ -736,22 +741,31 @@ static void sh532u_sts_rd(struct sh532u_info *info)
}
}
-static s16 sh532u_rel2abs(struct sh532u_info *info, u32 rel_position)
+static s16 sh532u_rel2abs(struct sh532u_info *info, s32 rel_position)
{
s16 abs_pos;
if (rel_position > info->cap.actuator_range)
rel_position = info->cap.actuator_range;
- rel_position = info->cap.actuator_range - rel_position;
- if (rel_position) {
- rel_position *= info->abs_range;
- rel_position /= info->cap.actuator_range;
+ if (info->cap.position_translate) {
+ rel_position = info->cap.actuator_range - rel_position;
+ if (rel_position) {
+ rel_position *= info->abs_range;
+ rel_position /= info->cap.actuator_range;
+ }
+ abs_pos = (s16)(info->abs_base + rel_position);
+ } else {
+ abs_pos = rel_position * SH532U_POS_SIGN_CHANGER;
}
- abs_pos = (s16)(info->abs_base + rel_position);
+
if (abs_pos < info->cfg.limit_low)
abs_pos = info->cfg.limit_low;
if (abs_pos > info->cfg.limit_high)
abs_pos = info->cfg.limit_high;
+
+ dev_dbg(&info->i2c_client->dev, "%s: rel_position %d returning abs_pos %d\n",
+ __func__, rel_position, abs_pos);
+
return abs_pos;
}
@@ -763,12 +777,21 @@ static u32 sh532u_abs2rel(struct sh532u_info *info, s16 abs_position)
abs_position = info->cfg.limit_high;
if (abs_position < info->abs_base)
abs_position = info->abs_base;
- rel_pos = (u32)(abs_position - info->abs_base);
- rel_pos *= info->cap.actuator_range;
- rel_pos /= info->abs_range;
- if (rel_pos > info->cap.actuator_range)
- rel_pos = info->cap.actuator_range;
- rel_pos = info->cap.actuator_range - rel_pos;
+
+ if (info->cap.position_translate) {
+ rel_pos = (u32)(abs_position - info->abs_base);
+ rel_pos *= info->cap.actuator_range;
+ rel_pos /= info->abs_range;
+
+ if (rel_pos > info->cap.actuator_range)
+ rel_pos = info->cap.actuator_range;
+ rel_pos = info->cap.actuator_range - rel_pos;
+ } else {
+ rel_pos = abs_position * SH532U_POS_SIGN_CHANGER;
+ }
+ dev_dbg(&info->i2c_client->dev, "%s: abs_position %d returning rel_pos %d",
+ __func__, abs_position, rel_pos);
+
return rel_pos;
}
@@ -782,7 +805,7 @@ static int sh532u_abs_pos_rd(struct sh532u_info *info, s16 *position)
return err;
}
-static int sh532u_rel_pos_rd(struct sh532u_info *info, u32 *position)
+static int sh532u_rel_pos_rd(struct sh532u_info *info, s32 *position)
{
s16 abs_pos;
long msec;
@@ -811,9 +834,11 @@ static int sh532u_rel_pos_rd(struct sh532u_info *info, u32 *position)
pos = (int)info->pos_rel;
}
}
- if (pos < 0)
- pos = 0;
- *position = (u32)pos;
+ if (info->cap.position_translate) {
+ if (pos < 0)
+ pos = 0;
+ }
+ *position = pos;
return 0;
}
@@ -851,6 +876,8 @@ static void sh532u_calibration_caps(struct sh532u_info *info)
rel_hi = info->cap.focus_infinity;
info->abs_range = (u32)(info->cfg.pos_high - info->cfg.pos_low);
loop_limit = (rel_lo > rel_hi) ? rel_lo : rel_hi;
+ dev_dbg(&info->i2c_client->dev, "%s: rel_lo %d rel_hi %d loop_limit %d\n",
+ __func__, rel_lo, rel_hi, loop_limit);
for (i = 0; i <= loop_limit; i++) {
rel_range = info->cap.actuator_range - (rel_lo + rel_hi);
step = info->abs_range / rel_range;
@@ -868,22 +895,36 @@ static void sh532u_calibration_caps(struct sh532u_info *info)
abs_top <= info->cfg.limit_high)
break;
}
+ dev_dbg(&info->i2c_client->dev, "%s: info->abs_range %d abs_base %d abs_top %d\n",
+ __func__, info->abs_range, info->abs_base, abs_top);
+
+ if (!info->cap.position_translate && info->abs_range)
+ info->cap.actuator_range = info->abs_range;
+
info->cap.focus_hyper = info->abs_range;
info->abs_range = (u32)(abs_top - info->abs_base);
/* calculate absolute hyperfocus position */
info->cap.focus_hyper *= info->cfg.focus_hyper_ratio;
info->cap.focus_hyper /= info->cfg.focus_hyper_div;
abs_top = (s16)(info->cfg.pos_high - info->cap.focus_hyper);
+
/* update actual relative positions */
info->cap.focus_hyper = sh532u_abs2rel(info, abs_top);
+ dev_dbg(&info->i2c_client->dev, "%s: focus_hyper abs %d rel %d\n",
+ __func__, abs_top, info->cap.focus_hyper);
+
info->cap.focus_infinity = sh532u_abs2rel(info, info->cfg.pos_high);
+ dev_dbg(&info->i2c_client->dev, "%s: focus_infinity abs %d rel %d\n",
+ __func__, info->cfg.pos_high, info->cap.focus_infinity);
+
info->cap.focus_macro = sh532u_abs2rel(info, info->cfg.pos_low);
- dev_dbg(&info->i2c_client->dev, "%s focus_macro=%u\n",
- __func__, info->cap.focus_macro);
- dev_dbg(&info->i2c_client->dev, "%s focus_infinity=%u\n",
- __func__, info->cap.focus_infinity);
- dev_dbg(&info->i2c_client->dev, "%s focus_hyper=%u\n",
- __func__, info->cap.focus_hyper);
+ dev_dbg(&info->i2c_client->dev, "%s: focus_macro abs %d rel %d\n",
+ __func__, info->cfg.pos_low, info->cap.focus_macro);
+
+ dev_dbg(&info->i2c_client->dev, "%s: Version %d actuator_range %d "
+ "settle_time %d position_traslate %d\n",
+ __func__, info->cap.version, info->cap.actuator_range,
+ info->cap.settle_time, info->cap.position_translate);
}
static int sh532u_calibration(struct sh532u_info *info, bool use_defaults)
@@ -892,8 +933,11 @@ static int sh532u_calibration(struct sh532u_info *info, bool use_defaults)
int err;
int ret = 0;
- if (info->init_cal_flag)
+ if (info->init_cal_flag) {
+ dev_dbg(&info->i2c_client->dev, "%s: Already initialized"
+ "Returning\n", __func__);
return 0;
+ }
/*
* Get Inf1, Mac1
@@ -965,8 +1009,9 @@ static int sh532u_calibration(struct sh532u_info *info, bool use_defaults)
* 1 PASS PASS Continue to calculations
*/
/* err = DATA where FAIL = 1 */
- if (!info->cfg.pos_low || !info->cfg.pos_high ||
- !info->cfg.limit_low || !info->cfg.limit_high)
+ if (!info->cfg.pos_low || info->cfg.pos_high <= info->cfg.pos_low ||
+ !info->cfg.limit_low ||
+ info->cfg.limit_high <= info->cfg.limit_low)
err = 1;
else
err = 0;
@@ -998,6 +1043,7 @@ static int sh532u_calibration(struct sh532u_info *info, bool use_defaults)
__func__, (int)info->cfg.limit_low);
dev_dbg(&info->i2c_client->dev, "%s limit_high=%d\n",
__func__, (int)info->cfg.limit_high);
+
sh532u_calibration_caps(info);
info->init_cal_flag = 1;
dev_dbg(&info->i2c_client->dev, "%s complete\n", __func__);
@@ -1215,6 +1261,7 @@ static int sh532u_pos_abs_wr(struct sh532u_info *info, s16 tar_pos)
STMLFF_OFF |
STMVEN_ON));
}
+ dev_dbg(&info->i2c_client->dev, "%s: position %d\n", __func__, tar_pos);
return err;
}
@@ -1289,30 +1336,101 @@ static int sh532u_hvca_pos_init(struct sh532u_info *info)
return err;
}
-static int sh532u_pos_rel_wr(struct sh532u_info *info, u32 position)
+static int sh532u_pos_rel_wr(struct sh532u_info *info, s32 position)
{
s16 abs_pos;
- if (position > info->cap.actuator_range) {
- dev_err(&info->i2c_client->dev, "%s invalid position %u\n",
- __func__, position);
- return -EINVAL;
+ if (info->cap.position_translate) {
+ if (position > info->cap.actuator_range) {
+ dev_err(&info->i2c_client->dev, "%s invalid position %d\n",
+ __func__, position);
+ return -EINVAL;
+ }
}
-
abs_pos = sh532u_rel2abs(info, position);
+
info->pos_rel = position;
info->pos_abs = abs_pos;
info->pos_time_wr = jiffies;
return sh532u_pos_abs_wr(info, abs_pos);
}
+static void sh532u_get_focuser_capabilities(struct sh532u_info *info)
+{
+ memset(&info->config, 0, sizeof(info->config));
+
+ info->config.focal_length = info->nvc.focal_length;
+ info->config.fnumber = info->nvc.fnumber;
+ info->config.max_aperture = info->nvc.fnumber;
+ info->config.range_ends_reversed = (SH532U_POS_SIGN_CHANGER == -1)
+ ? 1 : 0;
+
+ info->config.settle_time = info->cap.settle_time;
+
+ /*
+ * We do not use pos_working_low and pos_working_high
+ * in the kernel driver.
+ */
+ info->config.pos_working_low = AF_POS_INVALID_VALUE;
+ info->config.pos_working_high = AF_POS_INVALID_VALUE;
+
+ info->config.pos_actual_low = info->cfg.limit_high *
+ SH532U_POS_SIGN_CHANGER;
+ info->config.pos_actual_high = info->cfg.limit_low *
+ SH532U_POS_SIGN_CHANGER;
+ info->config.slew_rate = info->cap.slew_rate;
+ info->config.circle_of_confusion = -1;
+
+ /*
+ * These need to be passed up once we have the EEPROM/OTP read
+ * routines in teh kernel. These need to be passed up much earlier on.
+ * Till we have these routines, we pass them up as part of the get call.
+ */
+ info->config.num_focuser_sets = 1;
+ info->config.focuser_set[0].posture = 'S';
+ info->config.focuser_set[0].macro = info->cap.focus_macro;
+ info->config.focuser_set[0].hyper = info->cap.focus_hyper;
+ info->config.focuser_set[0].inf = info->cap.focus_infinity;
+ info->config.focuser_set[0].hysteresis = 0;
+ info->config.focuser_set[0].settle_time = info->cap.settle_time;
+ info->config.focuser_set[0].num_dist_pairs = 0;
+
+ dev_dbg(&info->i2c_client->dev, "%s: pos_actual_low %d pos_actual_high %d "
+ " settle_time %d\n", __func__, info->config.pos_actual_low,
+ info->config.pos_actual_high, info->cap.settle_time);
+
+}
+
+
+static int sh532u_set_focuser_capabilities(struct sh532u_info *info,
+ struct nvc_param *params)
+{
+ if (copy_from_user(&info->config, (const void __user *)params->p_value,
+ params->sizeofvalue)) {
+ dev_err(&info->i2c_client->dev, "%s Error: copy_from_user bytes %d\n",
+ __func__, params->sizeofvalue);
+ return -EFAULT;
+ }
+
+ /* info.config.focuser_set[0].posture, macro, hyper, infinity and
+ * hysterisis can remain there only. We need only settle_time &
+ * slew_rate for use here.
+ */
+ info->cap.settle_time = info->config.focuser_set[0].settle_time;
+ info->config.slew_rate = info->config.slew_rate;
+
+ dev_dbg(&info->i2c_client->dev, "%s: copy_from_user bytes %d\n",
+ __func__, params->sizeofvalue);
+ return 0;
+}
+
static int sh532u_param_rd(struct sh532u_info *info, unsigned long arg)
{
struct nvc_param params;
const void *data_ptr;
u32 data_size = 0;
- u32 position;
+ s32 position;
int err;
if (copy_from_user(&params,
@@ -1366,16 +1484,14 @@ static int sh532u_param_rd(struct sh532u_info *info, unsigned long arg)
sh532u_pm_dev_wr(info, NVC_PWR_STDBY);
if (err)
return -EIO;
+ dev_dbg(&info->i2c_client->dev, "%s: NVC_PARAM_CAPS: params.param %d "
+ "params.sizeofvalue %d\n",
+ __func__, params.param, params.sizeofvalue);
- data_ptr = &info->cap;
- /* there are different sizes depending on the version */
- /* send back just what's requested or our max size */
- if (params.sizeofvalue < sizeof(info->cap))
- data_size = params.sizeofvalue;
- else
- data_size = sizeof(info->cap);
- dev_dbg(&info->i2c_client->dev, "%s CAPS\n",
- __func__);
+ sh532u_get_focuser_capabilities(info);
+
+ data_ptr = &info->config;
+ data_size = params.sizeofvalue;
break;
case NVC_PARAM_STS:
@@ -1421,16 +1537,15 @@ static int sh532u_param_wr_s(struct sh532u_info *info,
struct nvc_param *params,
u32 u32val)
{
- struct nvc_focus_cap cap;
u8 u8val;
int err;
u8val = (u8)u32val;
switch (params->param) {
case NVC_PARAM_LOCUS:
- dev_dbg(&info->i2c_client->dev, "%s LOCUS: %u\n",
- __func__, u32val);
- err = sh532u_pos_rel_wr(info, u32val);
+ dev_dbg(&info->i2c_client->dev, "%s LOCUS: %d\n",
+ __func__, (s32) u32val);
+ err = sh532u_pos_rel_wr(info, (s32) u32val);
return err;
case NVC_PARAM_RESET:
@@ -1446,27 +1561,9 @@ static int sh532u_param_wr_s(struct sh532u_info *info,
return err;
case NVC_PARAM_CAPS:
- dev_dbg(&info->i2c_client->dev, "%s CAPS\n",
- __func__);
- if (copy_from_user(&cap, (const void __user *)params->p_value,
- sizeof(params->sizeofvalue))) {
- dev_err(&info->i2c_client->dev, "%s %d copy_from_user err\n",
- __func__, __LINE__);
- return -EFAULT;
- }
-
- if (!cap.version)
- return -EINVAL;
-
- if (cap.version >= NVC_FOCUS_CAP_VER1)
- info->cap.actuator_range = cap.actuator_range;
- if (cap.version >= NVC_FOCUS_CAP_VER2) {
- info->cap.focus_macro = cap.focus_macro;
- info->cap.focus_hyper = cap.focus_hyper;
- info->cap.focus_infinity = cap.focus_infinity;
- }
- sh532u_calibration_caps(info);
- return 0;
+ dev_dbg(&info->i2c_client->dev, "%s CAPS. Error. sh532u_param_wr "
+ "should be called instead\n", __func__);
+ return -EFAULT;
default:
dev_dbg(&info->i2c_client->dev,
@@ -1575,6 +1672,14 @@ static int sh532u_param_wr(struct sh532u_info *info, unsigned long arg)
return err;
+ case NVC_PARAM_CAPS:
+ if (sh532u_set_focuser_capabilities(info, &params)) {
+ dev_err(&info->i2c_client->dev, "%s: Error: copy_from_user bytes %d\n",
+ __func__, params.sizeofvalue);
+ return -EFAULT;
+ }
+ return 0;
+
default:
/* parameters dependent on sync mode */
switch (info->s_mode) {
@@ -1773,6 +1878,7 @@ static int sh532u_open(struct inode *inode, struct file *file)
file->private_data = info;
dev_dbg(&info->i2c_client->dev, "%s\n", __func__);
sh532u_pos_rel_wr(info, info->cap.focus_infinity);
+ sh532u_pm_wr_s(info, NVC_PWR_OFF);
return 0;
}
@@ -1828,7 +1934,6 @@ static int sh532u_probe(
char dname[16];
int err;
- dev_dbg(&client->dev, "%s\n", __func__);
info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL);
if (info == NULL) {
dev_err(&client->dev, "%s: kzalloc error\n", __func__);
diff --git a/drivers/media/video/tegra/tegra_camera.c b/drivers/media/video/tegra/tegra_camera.c
index 36ecde087bed..03eecf464c48 100644
--- a/drivers/media/video/tegra/tegra_camera.c
+++ b/drivers/media/video/tegra/tegra_camera.c
@@ -96,25 +96,18 @@ static int tegra_camera_disable_clk(struct tegra_camera_dev *dev)
static int tegra_camera_enable_emc(struct tegra_camera_dev *dev)
{
- /*
- * tegra_camera wasn't added as a user of emc_clk until 3x.
- * set to 150 MHz, will likely need to be increased as we support
- * sensors with higher framerates and resolutions.
- */
+ int ret = tegra_emc_disable_eack();
clk_enable(dev->emc_clk);
-
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
clk_set_rate(dev->emc_clk, 300000000);
-#else
- clk_set_rate(dev->emc_clk, 150000000);
#endif
- return 0;
+ return ret;
}
static int tegra_camera_disable_emc(struct tegra_camera_dev *dev)
{
clk_disable(dev->emc_clk);
- return 0;
+ return tegra_emc_enable_eack();
}
static int tegra_camera_clk_set_rate(struct tegra_camera_dev *dev)
@@ -130,7 +123,8 @@ static int tegra_camera_clk_set_rate(struct tegra_camera_dev *dev)
return -EINVAL;
}
- if (info->id != TEGRA_CAMERA_MODULE_VI) {
+ if (info->id != TEGRA_CAMERA_MODULE_VI &&
+ info->id != TEGRA_CAMERA_MODULE_EMC) {
dev_err(dev->dev,
"%s: set rate only aplies to vi module %d\n",
__func__, info->id);
@@ -144,6 +138,14 @@ static int tegra_camera_clk_set_rate(struct tegra_camera_dev *dev)
case TEGRA_CAMERA_VI_SENSOR_CLK:
clk = dev->vi_sensor_clk;
break;
+ case TEGRA_CAMERA_EMC_CLK:
+ clk = dev->emc_clk;
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+ dev_dbg(dev->dev, "%s: emc_clk rate=%lu\n",
+ __func__, info->rate);
+ clk_set_rate(dev->emc_clk, info->rate);
+#endif
+ goto set_rate_end;
default:
dev_err(dev->dev,
"%s: invalid clk id for set rate %d\n",
@@ -182,13 +184,17 @@ static int tegra_camera_clk_set_rate(struct tegra_camera_dev *dev)
tegra_clk_cfg_ex(clk, TEGRA_CLK_VI_INP_SEL, 2);
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- u32 val;
- void __iomem *apb_misc = IO_ADDRESS(TEGRA_APB_MISC_BASE);
- val = readl(apb_misc + 0x42c);
- writel(val | 0x1, apb_misc + 0x42c);
+ {
+ u32 val;
+ void __iomem *apb_misc =
+ IO_ADDRESS(TEGRA_APB_MISC_BASE);
+ val = readl(apb_misc + 0x42c);
+ writel(val | 0x1, apb_misc + 0x42c);
+ }
#endif
}
+set_rate_end:
info->rate = clk_get_rate(clk);
dev_dbg(dev->dev, "%s: get_rate=%lu",
__func__, info->rate);
diff --git a/drivers/media/video/tegra/tegra_dtv.c b/drivers/media/video/tegra/tegra_dtv.c
index 8a53930aec7a..f0b9a0a33a33 100644
--- a/drivers/media/video/tegra/tegra_dtv.c
+++ b/drivers/media/video/tegra/tegra_dtv.c
@@ -921,6 +921,7 @@ static int tegra_dtv_probe(struct platform_device *pdev)
ret = -EIO;
goto fail_no_clk;
}
+ dtv_ctx->clk = clk;
ret = clk_enable(clk);
if (ret < 0) {
dev_err(&pdev->dev, "cannot enable clk for tegra_dtv.\n");
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index f89c3eedee36..f37d3ec02123 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -175,7 +175,6 @@ config MFD_TPS65910
bool "TPS65910 Power Management chip"
depends on I2C=y && GPIOLIB
select MFD_CORE
- select GPIO_TPS65910
select REGMAP_I2C
help
if you say yes here you get support for the TPS65910 series of
@@ -868,6 +867,16 @@ config MFD_RICOH583
additional drivers must be enabled in order to use the
functionality of the device.
+config MFD_PALMAS
+ bool "Support for the TI Palmas series chips"
+ select MFD_CORE
+ select REGMAP_I2C
+ select REGMAP_IRQ
+ depends on I2C=y
+ help
+ If you say yes here you get support for the Palmas
+ series of PMIC chips from Texas Instruments.
+
endif # MFD_SUPPORT
menu "Multimedia Capabilities Port drivers"
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 90f02cdc538a..6634515b64e4 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -111,3 +111,5 @@ obj-$(CONFIG_MFD_MAX8907C) += max8907c-irq.o
obj-$(CONFIG_MFD_MAX77663) += max77663-core.o
obj-$(CONFIG_MFD_RICOH583) += ricoh583.o
obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o
+obj-$(CONFIG_MFD_PALMAS) += palmas.o
+obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o
diff --git a/drivers/mfd/max77663-core.c b/drivers/mfd/max77663-core.c
index ff47cb123d0d..46728c331f83 100644
--- a/drivers/mfd/max77663-core.c
+++ b/drivers/mfd/max77663-core.c
@@ -118,6 +118,8 @@
#define ONOFF_SLP_LPM_MASK (1 << 5)
+#define ONOFF_IRQ_EN0_RISING (1 << 3)
+
enum {
CACHE_IRQ_LBT,
CACHE_IRQ_SD,
@@ -903,6 +905,8 @@ static void max77663_irq_sync_unlock(struct irq_data *data)
irq_mask = irq_data->trigger_type;
else
irq_mask = GPIO_REFE_IRQ_EDGE_FALLING << shift;
+ } else {
+ irq_mask = GPIO_REFE_IRQ_NONE << shift;
}
ret = max77663_cache_write(chip->dev, GPIO_REG_ADDR(offset),
@@ -1132,6 +1136,10 @@ static int max77663_irq_init(struct max77663_chip *chip)
max77663_write(chip->dev, MAX77663_REG_LBT_IRQ_MASK,
&chip->cache_irq_mask[CACHE_IRQ_LBT], 1, 0);
+ chip->cache_irq_mask[CACHE_IRQ_ONOFF] &= ~ONOFF_IRQ_EN0_RISING;
+ max77663_write(chip->dev, MAX77663_REG_ONOFF_IRQ_MASK,
+ &chip->cache_irq_mask[CACHE_IRQ_ONOFF], 1, 0);
+
return 0;
}
diff --git a/drivers/mfd/palmas.c b/drivers/mfd/palmas.c
new file mode 100644
index 000000000000..00c0aba7eba0
--- /dev/null
+++ b/drivers/mfd/palmas.c
@@ -0,0 +1,509 @@
+/*
+ * TI Palmas MFD Driver
+ *
+ * Copyright 2011-2012 Texas Instruments Inc.
+ *
+ * Author: Graeme Gregory <gg@slimlogic.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/regmap.h>
+#include <linux/err.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/palmas.h>
+
+static const struct resource gpadc_resource[] = {
+ {
+ .name = "EOC_SW",
+ .start = PALMAS_GPADC_EOC_SW_IRQ,
+ .end = PALMAS_GPADC_EOC_SW_IRQ,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static const struct resource usb_resource[] = {
+ {
+ .name = "ID",
+ .start = PALMAS_ID_OTG_IRQ,
+ .end = PALMAS_ID_OTG_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "ID_WAKEUP",
+ .start = PALMAS_ID_IRQ,
+ .end = PALMAS_ID_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "VBUS",
+ .start = PALMAS_VBUS_OTG_IRQ,
+ .end = PALMAS_VBUS_OTG_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "VBUS_WAKEUP",
+ .start = PALMAS_VBUS_IRQ,
+ .end = PALMAS_VBUS_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static const struct resource rtc_resource[] = {
+ {
+ .name = "RTC_ALARM",
+ .start = PALMAS_RTC_ALARM_IRQ,
+ .end = PALMAS_RTC_ALARM_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static const struct resource pwron_resource[] = {
+ {
+ .name = "PWRON_BUTTON",
+ .start = PALMAS_PWRON_IRQ,
+ .end = PALMAS_PWRON_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+enum palmas_ids {
+ PALMAS_PMIC_ID,
+ PALMAS_GPIO_ID,
+ PALMAS_LEDS_ID,
+ PALMAS_WDT_ID,
+ PALMAS_RTC_ID,
+ PALMAS_PWRBUTTON_ID,
+ PALMAS_GPADC_ID,
+ PALMAS_RESOURCE_ID,
+ PALMAS_CLK_ID,
+ PALMAS_PWM_ID,
+ PALMAS_USB_ID,
+};
+
+static const struct mfd_cell palmas_children[] = {
+ {
+ .name = "palmas-pmic",
+ .id = PALMAS_PMIC_ID,
+ },
+ {
+ .name = "palmas-gpio",
+ .id = PALMAS_GPIO_ID,
+ },
+ {
+ .name = "palmas-leds",
+ .id = PALMAS_LEDS_ID,
+ },
+ {
+ .name = "palmas-wdt",
+ .id = PALMAS_WDT_ID,
+ },
+ {
+ .name = "palmas-rtc",
+ .num_resources = ARRAY_SIZE(rtc_resource),
+ .resources = rtc_resource,
+ .id = PALMAS_RTC_ID,
+ },
+ {
+ .name = "palmas-pwrbutton",
+ .num_resources = ARRAY_SIZE(pwron_resource),
+ .resources = pwron_resource,
+ .id = PALMAS_PWRBUTTON_ID,
+ },
+ {
+ .name = "palmas-gpadc",
+ .num_resources = ARRAY_SIZE(gpadc_resource),
+ .resources = gpadc_resource,
+ .id = PALMAS_GPADC_ID,
+ },
+ {
+ .name = "palmas-resource",
+ .id = PALMAS_RESOURCE_ID,
+ },
+ {
+ .name = "palmas-clk",
+ .id = PALMAS_CLK_ID,
+ },
+ {
+ .name = "palmas-pwm",
+ .id = PALMAS_PWM_ID,
+ },
+ {
+ .name = "palmas-usb",
+ .num_resources = ARRAY_SIZE(usb_resource),
+ .resources = usb_resource,
+ .id = PALMAS_USB_ID,
+ }
+};
+
+static const struct regmap_config palmas_regmap_config[PALMAS_NUM_CLIENTS] = {
+ {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = PALMAS_BASE_TO_REG(PALMAS_PU_PD_OD_BASE,
+ PALMAS_PRIMARY_SECONDARY_PAD3),
+ },
+ {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = PALMAS_BASE_TO_REG(PALMAS_GPADC_BASE,
+ PALMAS_GPADC_SMPS_VSEL_MONITORING),
+ },
+ {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = PALMAS_BASE_TO_REG(PALMAS_TRIM_GPADC_BASE,
+ PALMAS_GPADC_TRIM16),
+ },
+};
+
+static const struct regmap_irq palmas_irqs[] = {
+ /* INT1 IRQs */
+ [PALMAS_CHARG_DET_N_VBUS_OVV_IRQ] = {
+ .mask = PALMAS_INT1_STATUS_CHARG_DET_N_VBUS_OVV,
+ },
+ [PALMAS_PWRON_IRQ] = {
+ .mask = PALMAS_INT1_STATUS_PWRON,
+ },
+ [PALMAS_LONG_PRESS_KEY_IRQ] = {
+ .mask = PALMAS_INT1_STATUS_LONG_PRESS_KEY,
+ },
+ [PALMAS_RPWRON_IRQ] = {
+ .mask = PALMAS_INT1_STATUS_RPWRON,
+ },
+ [PALMAS_PWRDOWN_IRQ] = {
+ .mask = PALMAS_INT1_STATUS_PWRDOWN,
+ },
+ [PALMAS_HOTDIE_IRQ] = {
+ .mask = PALMAS_INT1_STATUS_HOTDIE,
+ },
+ [PALMAS_VSYS_MON_IRQ] = {
+ .mask = PALMAS_INT1_STATUS_VSYS_MON,
+ },
+ [PALMAS_VBAT_MON_IRQ] = {
+ .mask = PALMAS_INT1_STATUS_VBAT_MON,
+ },
+ /* INT2 IRQs*/
+ [PALMAS_RTC_ALARM_IRQ] = {
+ .mask = PALMAS_INT2_STATUS_RTC_ALARM,
+ .reg_offset = 1,
+ },
+ [PALMAS_RTC_TIMER_IRQ] = {
+ .mask = PALMAS_INT2_STATUS_RTC_TIMER,
+ .reg_offset = 1,
+ },
+ [PALMAS_WDT_IRQ] = {
+ .mask = PALMAS_INT2_STATUS_WDT,
+ .reg_offset = 1,
+ },
+ [PALMAS_BATREMOVAL_IRQ] = {
+ .mask = PALMAS_INT2_STATUS_BATREMOVAL,
+ .reg_offset = 1,
+ },
+ [PALMAS_RESET_IN_IRQ] = {
+ .mask = PALMAS_INT2_STATUS_RESET_IN,
+ .reg_offset = 1,
+ },
+ [PALMAS_FBI_BB_IRQ] = {
+ .mask = PALMAS_INT2_STATUS_FBI_BB,
+ .reg_offset = 1,
+ },
+ [PALMAS_SHORT_IRQ] = {
+ .mask = PALMAS_INT2_STATUS_SHORT,
+ .reg_offset = 1,
+ },
+ [PALMAS_VAC_ACOK_IRQ] = {
+ .mask = PALMAS_INT2_STATUS_VAC_ACOK,
+ .reg_offset = 1,
+ },
+ /* INT3 IRQs */
+ [PALMAS_GPADC_AUTO_0_IRQ] = {
+ .mask = PALMAS_INT3_STATUS_GPADC_AUTO_0,
+ .reg_offset = 2,
+ },
+ [PALMAS_GPADC_AUTO_1_IRQ] = {
+ .mask = PALMAS_INT3_STATUS_GPADC_AUTO_1,
+ .reg_offset = 2,
+ },
+ [PALMAS_GPADC_EOC_SW_IRQ] = {
+ .mask = PALMAS_INT3_STATUS_GPADC_EOC_SW,
+ .reg_offset = 2,
+ },
+ [PALMAS_GPADC_EOC_RT_IRQ] = {
+ .mask = PALMAS_INT3_STATUS_GPADC_EOC_RT,
+ .reg_offset = 2,
+ },
+ [PALMAS_ID_OTG_IRQ] = {
+ .mask = PALMAS_INT3_STATUS_ID_OTG,
+ .reg_offset = 2,
+ },
+ [PALMAS_ID_IRQ] = {
+ .mask = PALMAS_INT3_STATUS_ID,
+ .reg_offset = 2,
+ },
+ [PALMAS_VBUS_OTG_IRQ] = {
+ .mask = PALMAS_INT3_STATUS_VBUS_OTG,
+ .reg_offset = 2,
+ },
+ [PALMAS_VBUS_IRQ] = {
+ .mask = PALMAS_INT3_STATUS_VBUS,
+ .reg_offset = 2,
+ },
+ /* INT4 IRQs */
+ [PALMAS_GPIO_0_IRQ] = {
+ .mask = PALMAS_INT4_STATUS_GPIO_0,
+ .reg_offset = 3,
+ },
+ [PALMAS_GPIO_1_IRQ] = {
+ .mask = PALMAS_INT4_STATUS_GPIO_1,
+ .reg_offset = 3,
+ },
+ [PALMAS_GPIO_2_IRQ] = {
+ .mask = PALMAS_INT4_STATUS_GPIO_2,
+ .reg_offset = 3,
+ },
+ [PALMAS_GPIO_3_IRQ] = {
+ .mask = PALMAS_INT4_STATUS_GPIO_3,
+ .reg_offset = 3,
+ },
+ [PALMAS_GPIO_4_IRQ] = {
+ .mask = PALMAS_INT4_STATUS_GPIO_4,
+ .reg_offset = 3,
+ },
+ [PALMAS_GPIO_5_IRQ] = {
+ .mask = PALMAS_INT4_STATUS_GPIO_5,
+ .reg_offset = 3,
+ },
+ [PALMAS_GPIO_6_IRQ] = {
+ .mask = PALMAS_INT4_STATUS_GPIO_6,
+ .reg_offset = 3,
+ },
+ [PALMAS_GPIO_7_IRQ] = {
+ .mask = PALMAS_INT4_STATUS_GPIO_7,
+ .reg_offset = 3,
+ },
+};
+
+static struct regmap_irq_chip palmas_irq_chip = {
+ .name = "palmas",
+ .irqs = palmas_irqs,
+ .num_irqs = ARRAY_SIZE(palmas_irqs),
+
+ .num_regs = 4,
+ .irq_reg_stride = 5,
+ .status_base = PALMAS_BASE_TO_REG(PALMAS_INTERRUPT_BASE,
+ PALMAS_INT1_STATUS),
+ .mask_base = PALMAS_BASE_TO_REG(PALMAS_INTERRUPT_BASE,
+ PALMAS_INT1_MASK),
+};
+
+static int __devinit palmas_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct palmas *palmas;
+ struct palmas_platform_data *pdata;
+ int ret = 0, i;
+ unsigned int reg, addr;
+ int slave;
+ struct mfd_cell *children;
+
+ pdata = dev_get_platdata(&i2c->dev);
+ if (!pdata)
+ return -EINVAL;
+
+ palmas = devm_kzalloc(&i2c->dev, sizeof(struct palmas), GFP_KERNEL);
+ if (palmas == NULL)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, palmas);
+ palmas->dev = &i2c->dev;
+ palmas->id = id->driver_data;
+ palmas->irq = i2c->irq;
+
+ for (i = 0; i < PALMAS_NUM_CLIENTS; i++) {
+ if (i == 0)
+ palmas->i2c_clients[i] = i2c;
+ else {
+ palmas->i2c_clients[i] =
+ i2c_new_dummy(i2c->adapter,
+ i2c->addr + i);
+ if (!palmas->i2c_clients[i]) {
+ dev_err(palmas->dev,
+ "can't attach client %d\n", i);
+ ret = -ENOMEM;
+ goto err;
+ }
+ }
+ palmas->regmap[i] = devm_regmap_init_i2c(palmas->i2c_clients[i],
+ &palmas_regmap_config[i]);
+ if (IS_ERR(palmas->regmap[i])) {
+ ret = PTR_ERR(palmas->regmap[i]);
+ dev_err(palmas->dev,
+ "Failed to allocate regmap %d, err: %d\n",
+ i, ret);
+ goto err;
+ }
+ }
+
+ ret = regmap_add_irq_chip(palmas->regmap[1], palmas->irq,
+ IRQF_ONESHOT | IRQF_TRIGGER_LOW, -1, &palmas_irq_chip,
+ &palmas->irq_data);
+ if (ret < 0)
+ goto err;
+
+ slave = PALMAS_BASE_TO_SLAVE(PALMAS_PU_PD_OD_BASE);
+ addr = PALMAS_BASE_TO_REG(PALMAS_PU_PD_OD_BASE,
+ PALMAS_PRIMARY_SECONDARY_PAD1);
+
+ if (pdata->mux_from_pdata) {
+ reg = pdata->pad1;
+ ret = regmap_write(palmas->regmap[slave], addr, reg);
+ if (ret)
+ goto err;
+ } else {
+ ret = regmap_read(palmas->regmap[slave], addr, &reg);
+ if (ret)
+ goto err;
+ }
+
+ if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_0))
+ palmas->gpio_muxed |= PALMAS_GPIO_0_MUXED;
+ if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_MASK))
+ palmas->gpio_muxed |= PALMAS_GPIO_1_MUXED;
+ else if ((reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_MASK) ==
+ (2 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_SHIFT))
+ palmas->led_muxed |= PALMAS_LED1_MUXED;
+ else if ((reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_MASK) ==
+ (3 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_SHIFT))
+ palmas->pwm_muxed |= PALMAS_PWM1_MUXED;
+ if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_MASK))
+ palmas->gpio_muxed |= PALMAS_GPIO_2_MUXED;
+ else if ((reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_MASK) ==
+ (2 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_SHIFT))
+ palmas->led_muxed |= PALMAS_LED2_MUXED;
+ else if ((reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_MASK) ==
+ (3 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_SHIFT))
+ palmas->pwm_muxed |= PALMAS_PWM2_MUXED;
+ if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_3))
+ palmas->gpio_muxed |= PALMAS_GPIO_3_MUXED;
+
+ addr = PALMAS_BASE_TO_REG(PALMAS_PU_PD_OD_BASE,
+ PALMAS_PRIMARY_SECONDARY_PAD2);
+
+ if (pdata->mux_from_pdata) {
+ reg = pdata->pad2;
+ ret = regmap_write(palmas->regmap[slave], addr, reg);
+ if (ret)
+ goto err;
+ } else {
+ ret = regmap_read(palmas->regmap[slave], addr, &reg);
+ if (ret)
+ goto err;
+ }
+
+ if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_4))
+ palmas->gpio_muxed |= PALMAS_GPIO_4_MUXED;
+ if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_5_MASK))
+ palmas->gpio_muxed |= PALMAS_GPIO_5_MUXED;
+ if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_6))
+ palmas->gpio_muxed |= PALMAS_GPIO_6_MUXED;
+ if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_7_MASK))
+ palmas->gpio_muxed |= PALMAS_GPIO_7_MUXED;
+
+ dev_info(palmas->dev, "Muxing GPIO %x, PWM %x, LED %x\n",
+ palmas->gpio_muxed, palmas->pwm_muxed,
+ palmas->led_muxed);
+
+ reg = pdata->power_ctrl;
+
+ slave = PALMAS_BASE_TO_SLAVE(PALMAS_PMU_CONTROL_BASE);
+ addr = PALMAS_BASE_TO_REG(PALMAS_PMU_CONTROL_BASE, PALMAS_POWER_CTRL);
+
+ ret = regmap_write(palmas->regmap[slave], addr, reg);
+ if (ret)
+ goto err;
+
+ children = kmemdup(palmas_children, sizeof(palmas_children),
+ GFP_KERNEL);
+ if (!children) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ ret = mfd_add_devices(palmas->dev, -1,
+ children, ARRAY_SIZE(palmas_children),
+ NULL, regmap_irq_chip_get_base(palmas->irq_data));
+ kfree(children);
+
+ if (ret < 0)
+ goto err;
+
+ return ret;
+
+err:
+ mfd_remove_devices(palmas->dev);
+ kfree(palmas);
+ return ret;
+}
+
+static int palmas_i2c_remove(struct i2c_client *i2c)
+{
+ struct palmas *palmas = i2c_get_clientdata(i2c);
+
+ mfd_remove_devices(palmas->dev);
+ regmap_del_irq_chip(palmas->irq, palmas->irq_data);
+
+ return 0;
+}
+
+static const struct i2c_device_id palmas_i2c_id[] = {
+ { "palmas", },
+ { "twl6035", },
+ { "twl6037", },
+ { "tps65913", },
+};
+MODULE_DEVICE_TABLE(i2c, palmas_i2c_id);
+
+static struct of_device_id __devinitdata of_palmas_match_tbl[] = {
+ { .compatible = "ti,palmas", },
+ { /* end */ }
+};
+
+static struct i2c_driver palmas_i2c_driver = {
+ .driver = {
+ .name = "palmas",
+ .of_match_table = of_palmas_match_tbl,
+ .owner = THIS_MODULE,
+ },
+ .probe = palmas_i2c_probe,
+ .remove = palmas_i2c_remove,
+ .id_table = palmas_i2c_id,
+};
+
+static int __init palmas_i2c_init(void)
+{
+ return i2c_add_driver(&palmas_i2c_driver);
+}
+/* init early so consumer devices can complete system boot */
+subsys_initcall(palmas_i2c_init);
+
+static void __exit palmas_i2c_exit(void)
+{
+ i2c_del_driver(&palmas_i2c_driver);
+}
+module_exit(palmas_i2c_exit);
+
+MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>");
+MODULE_DESCRIPTION("Palmas chip family multi-function driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/rc5t583.c b/drivers/mfd/rc5t583.c
index 99ef944c621d..cdc1df7fa0e9 100644
--- a/drivers/mfd/rc5t583.c
+++ b/drivers/mfd/rc5t583.c
@@ -75,49 +75,12 @@ static struct deepsleep_control_data deepsleep_data[] = {
(RC5T583_EXT_PWRREQ1_CONTROL | RC5T583_EXT_PWRREQ2_CONTROL)
static struct mfd_cell rc5t583_subdevs[] = {
+ {.name = "rc5t583-gpio",},
{.name = "rc5t583-regulator",},
{.name = "rc5t583-rtc", },
{.name = "rc5t583-key", }
};
-int rc5t583_write(struct device *dev, uint8_t reg, uint8_t val)
-{
- struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
- return regmap_write(rc5t583->regmap, reg, val);
-}
-
-int rc5t583_read(struct device *dev, uint8_t reg, uint8_t *val)
-{
- struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
- unsigned int ival;
- int ret;
- ret = regmap_read(rc5t583->regmap, reg, &ival);
- if (!ret)
- *val = (uint8_t)ival;
- return ret;
-}
-
-int rc5t583_set_bits(struct device *dev, unsigned int reg,
- unsigned int bit_mask)
-{
- struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
- return regmap_update_bits(rc5t583->regmap, reg, bit_mask, bit_mask);
-}
-
-int rc5t583_clear_bits(struct device *dev, unsigned int reg,
- unsigned int bit_mask)
-{
- struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
- return regmap_update_bits(rc5t583->regmap, reg, bit_mask, 0);
-}
-
-int rc5t583_update(struct device *dev, unsigned int reg,
- unsigned int val, unsigned int mask)
-{
- struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
- return regmap_update_bits(rc5t583->regmap, reg, mask, val);
-}
-
static int __rc5t583_set_ext_pwrreq1_control(struct device *dev,
int id, int ext_pwr, int slots)
{
@@ -197,6 +160,7 @@ int rc5t583_ext_power_req_config(struct device *dev, int ds_id,
ds_id, ext_pwr_req);
return 0;
}
+EXPORT_SYMBOL(rc5t583_ext_power_req_config);
static int rc5t583_clear_ext_power_req(struct rc5t583 *rc5t583,
struct rc5t583_platform_data *pdata)
@@ -304,7 +268,7 @@ static int __devinit rc5t583_i2c_probe(struct i2c_client *i2c,
rc5t583->dev = &i2c->dev;
i2c_set_clientdata(i2c, rc5t583);
- rc5t583->regmap = regmap_init_i2c(i2c, &rc5t583_regmap_config);
+ rc5t583->regmap = devm_regmap_init_i2c(i2c, &rc5t583_regmap_config);
if (IS_ERR(rc5t583->regmap)) {
ret = PTR_ERR(rc5t583->regmap);
dev_err(&i2c->dev, "regmap initialization failed: %d\n", ret);
@@ -313,7 +277,7 @@ static int __devinit rc5t583_i2c_probe(struct i2c_client *i2c,
ret = rc5t583_clear_ext_power_req(rc5t583, pdata);
if (ret < 0)
- goto err_irq_init;
+ return ret;
if (i2c->irq) {
ret = rc5t583_irq_init(rc5t583, i2c->irq, pdata->irq_base);
@@ -336,8 +300,6 @@ static int __devinit rc5t583_i2c_probe(struct i2c_client *i2c,
err_add_devs:
if (irq_init_success)
rc5t583_irq_exit(rc5t583);
-err_irq_init:
- regmap_exit(rc5t583->regmap);
return ret;
}
@@ -347,7 +309,6 @@ static int __devexit rc5t583_i2c_remove(struct i2c_client *i2c)
mfd_remove_devices(rc5t583->dev);
rc5t583_irq_exit(rc5t583);
- regmap_exit(rc5t583->regmap);
return 0;
}
diff --git a/drivers/mfd/tps65910-irq.c b/drivers/mfd/tps65910-irq.c
index c9ed5c00a621..0f1ff7fbdc74 100644
--- a/drivers/mfd/tps65910-irq.c
+++ b/drivers/mfd/tps65910-irq.c
@@ -41,28 +41,28 @@ static inline int irq_to_tps65910_irq(struct tps65910 *tps65910,
static irqreturn_t tps65910_irq(int irq, void *irq_data)
{
struct tps65910 *tps65910 = irq_data;
+ unsigned int reg;
u32 irq_sts;
u32 irq_mask;
- u8 reg;
int i;
- tps65910->read(tps65910, TPS65910_INT_STS, 1, &reg);
+ tps65910_reg_read(tps65910, TPS65910_INT_STS, &reg);
irq_sts = reg;
- tps65910->read(tps65910, TPS65910_INT_STS2, 1, &reg);
+ tps65910_reg_read(tps65910, TPS65910_INT_STS2, &reg);
irq_sts |= reg << 8;
switch (tps65910_chip_id(tps65910)) {
case TPS65911:
- tps65910->read(tps65910, TPS65910_INT_STS3, 1, &reg);
+ tps65910_reg_read(tps65910, TPS65910_INT_STS3, &reg);
irq_sts |= reg << 16;
}
- tps65910->read(tps65910, TPS65910_INT_MSK, 1, &reg);
+ tps65910_reg_read(tps65910, TPS65910_INT_MSK, &reg);
irq_mask = reg;
- tps65910->read(tps65910, TPS65910_INT_MSK2, 1, &reg);
+ tps65910_reg_read(tps65910, TPS65910_INT_MSK2, &reg);
irq_mask |= reg << 8;
switch (tps65910_chip_id(tps65910)) {
case TPS65911:
- tps65910->read(tps65910, TPS65910_INT_MSK3, 1, &reg);
+ tps65910_reg_read(tps65910, TPS65910_INT_MSK3, &reg);
irq_mask |= reg << 16;
}
@@ -82,13 +82,13 @@ static irqreturn_t tps65910_irq(int irq, void *irq_data)
/* Write the STS register back to clear IRQs we handled */
reg = irq_sts & 0xFF;
irq_sts >>= 8;
- tps65910->write(tps65910, TPS65910_INT_STS, 1, &reg);
+ tps65910_reg_write(tps65910, TPS65910_INT_STS, reg);
reg = irq_sts & 0xFF;
- tps65910->write(tps65910, TPS65910_INT_STS2, 1, &reg);
+ tps65910_reg_write(tps65910, TPS65910_INT_STS2, reg);
switch (tps65910_chip_id(tps65910)) {
case TPS65911:
reg = irq_sts >> 8;
- tps65910->write(tps65910, TPS65910_INT_STS3, 1, &reg);
+ tps65910_reg_write(tps65910, TPS65910_INT_STS3, reg);
}
return IRQ_HANDLED;
@@ -105,27 +105,27 @@ static void tps65910_irq_sync_unlock(struct irq_data *data)
{
struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data);
u32 reg_mask;
- u8 reg;
+ unsigned int reg;
- tps65910->read(tps65910, TPS65910_INT_MSK, 1, &reg);
+ tps65910_reg_read(tps65910, TPS65910_INT_MSK, &reg);
reg_mask = reg;
- tps65910->read(tps65910, TPS65910_INT_MSK2, 1, &reg);
+ tps65910_reg_read(tps65910, TPS65910_INT_MSK2, &reg);
reg_mask |= reg << 8;
switch (tps65910_chip_id(tps65910)) {
case TPS65911:
- tps65910->read(tps65910, TPS65910_INT_MSK3, 1, &reg);
+ tps65910_reg_read(tps65910, TPS65910_INT_MSK3, &reg);
reg_mask |= reg << 16;
}
if (tps65910->irq_mask != reg_mask) {
reg = tps65910->irq_mask & 0xFF;
- tps65910->write(tps65910, TPS65910_INT_MSK, 1, &reg);
+ tps65910_reg_write(tps65910, TPS65910_INT_MSK, reg);
reg = tps65910->irq_mask >> 8 & 0xFF;
- tps65910->write(tps65910, TPS65910_INT_MSK2, 1, &reg);
+ tps65910_reg_write(tps65910, TPS65910_INT_MSK2, reg);
switch (tps65910_chip_id(tps65910)) {
case TPS65911:
reg = tps65910->irq_mask >> 16;
- tps65910->write(tps65910, TPS65910_INT_MSK3, 1, &reg);
+ tps65910_reg_write(tps65910, TPS65910_INT_MSK3, reg);
}
}
mutex_unlock(&tps65910->irq_lock);
diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c
index 1c4f53efee74..18b30cf45e5b 100644
--- a/drivers/mfd/tps65910.c
+++ b/drivers/mfd/tps65910.c
@@ -19,13 +19,16 @@
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/i2c.h>
-#include <linux/gpio.h>
#include <linux/mfd/core.h>
#include <linux/regmap.h>
#include <linux/mfd/tps65910.h>
+#include <linux/of_device.h>
static struct mfd_cell tps65910s[] = {
{
+ .name = "tps65910-gpio",
+ },
+ {
.name = "tps65910-pmic",
},
{
@@ -37,30 +40,6 @@ static struct mfd_cell tps65910s[] = {
};
-static int tps65910_i2c_read(struct tps65910 *tps65910, u8 reg,
- int bytes, void *dest)
-{
- return regmap_bulk_read(tps65910->regmap, reg, dest, bytes);
-}
-
-static int tps65910_i2c_write(struct tps65910 *tps65910, u8 reg,
- int bytes, void *src)
-{
- return regmap_bulk_write(tps65910->regmap, reg, src, bytes);
-}
-
-int tps65910_set_bits(struct tps65910 *tps65910, u8 reg, u8 mask)
-{
- return regmap_update_bits(tps65910->regmap, reg, mask, mask);
-}
-EXPORT_SYMBOL_GPL(tps65910_set_bits);
-
-int tps65910_clear_bits(struct tps65910 *tps65910, u8 reg, u8 mask)
-{
- return regmap_update_bits(tps65910->regmap, reg, mask, 0);
-}
-EXPORT_SYMBOL_GPL(tps65910_clear_bits);
-
static bool is_volatile_reg(struct device *dev, unsigned int reg)
{
struct tps65910 *tps65910 = dev_get_drvdata(dev);
@@ -81,84 +60,212 @@ static bool is_volatile_reg(struct device *dev, unsigned int reg)
return true;
}
-static const struct regmap_config rc5t583_regmap_config = {
+static const struct regmap_config tps65910_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.volatile_reg = is_volatile_reg,
- .max_register = TPS65910_MAX_REGISTER,
- .num_reg_defaults_raw = TPS65910_MAX_REGISTER,
+ .max_register = TPS65910_MAX_REGISTER - 1,
.cache_type = REGCACHE_RBTREE,
};
-static int tps65910_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+static int __devinit tps65910_sleepinit(struct tps65910 *tps65910,
+ struct tps65910_board *pmic_pdata)
+{
+ struct device *dev = NULL;
+ int ret = 0;
+
+ dev = tps65910->dev;
+
+ if (!pmic_pdata->en_dev_slp)
+ return 0;
+
+ /* enabling SLEEP device state */
+ ret = tps65910_reg_set_bits(tps65910, TPS65910_DEVCTRL,
+ DEVCTRL_DEV_SLP_MASK);
+ if (ret < 0) {
+ dev_err(dev, "set dev_slp failed: %d\n", ret);
+ goto err_sleep_init;
+ }
+
+ /* Return if there is no sleep keepon data. */
+ if (!pmic_pdata->slp_keepon)
+ return 0;
+
+ if (pmic_pdata->slp_keepon->therm_keepon) {
+ ret = tps65910_reg_set_bits(tps65910,
+ TPS65910_SLEEP_KEEP_RES_ON,
+ SLEEP_KEEP_RES_ON_THERM_KEEPON_MASK);
+ if (ret < 0) {
+ dev_err(dev, "set therm_keepon failed: %d\n", ret);
+ goto disable_dev_slp;
+ }
+ }
+
+ if (pmic_pdata->slp_keepon->clkout32k_keepon) {
+ ret = tps65910_reg_set_bits(tps65910,
+ TPS65910_SLEEP_KEEP_RES_ON,
+ SLEEP_KEEP_RES_ON_CLKOUT32K_KEEPON_MASK);
+ if (ret < 0) {
+ dev_err(dev, "set clkout32k_keepon failed: %d\n", ret);
+ goto disable_dev_slp;
+ }
+ }
+
+ if (pmic_pdata->slp_keepon->i2chs_keepon) {
+ ret = tps65910_reg_set_bits(tps65910,
+ TPS65910_SLEEP_KEEP_RES_ON,
+ SLEEP_KEEP_RES_ON_I2CHS_KEEPON_MASK);
+ if (ret < 0) {
+ dev_err(dev, "set i2chs_keepon failed: %d\n", ret);
+ goto disable_dev_slp;
+ }
+ }
+
+ return 0;
+
+disable_dev_slp:
+ tps65910_reg_clear_bits(tps65910, TPS65910_DEVCTRL,
+ DEVCTRL_DEV_SLP_MASK);
+
+err_sleep_init:
+ return ret;
+}
+
+#ifdef CONFIG_OF
+static struct of_device_id tps65910_of_match[] = {
+ { .compatible = "ti,tps65910", .data = (void *)TPS65910},
+ { .compatible = "ti,tps65911", .data = (void *)TPS65911},
+ { },
+};
+MODULE_DEVICE_TABLE(of, tps65910_of_match);
+
+static struct tps65910_board *tps65910_parse_dt(struct i2c_client *client,
+ int *chip_id)
+{
+ struct device_node *np = client->dev.of_node;
+ struct tps65910_board *board_info;
+ unsigned int prop;
+ const struct of_device_id *match;
+ unsigned int prop_array[TPS6591X_MAX_NUM_GPIO];
+ int ret = 0;
+ int idx;
+
+ match = of_match_device(tps65910_of_match, &client->dev);
+ if (!match) {
+ dev_err(&client->dev, "Failed to find matching dt id\n");
+ return NULL;
+ }
+
+ *chip_id = (int)match->data;
+
+ board_info = devm_kzalloc(&client->dev, sizeof(*board_info),
+ GFP_KERNEL);
+ if (!board_info) {
+ dev_err(&client->dev, "Failed to allocate pdata\n");
+ return NULL;
+ }
+
+ ret = of_property_read_u32(np, "ti,vmbch-threshold", &prop);
+ if (!ret)
+ board_info->vmbch_threshold = prop;
+ else if (*chip_id == TPS65911)
+ dev_warn(&client->dev, "VMBCH-Threshold not specified");
+
+ ret = of_property_read_u32(np, "ti,vmbch2-threshold", &prop);
+ if (!ret)
+ board_info->vmbch2_threshold = prop;
+ else if (*chip_id == TPS65911)
+ dev_warn(&client->dev, "VMBCH2-Threshold not specified");
+
+ ret = of_property_read_u32_array(np, "ti,en-gpio-sleep",
+ prop_array, TPS6591X_MAX_NUM_GPIO);
+ if (!ret)
+ for (idx = 0; idx < ARRAY_SIZE(prop_array); idx++)
+ board_info->en_gpio_sleep[idx] = (prop_array[idx] != 0);
+ else if (ret != -EINVAL) {
+ dev_err(&client->dev,
+ "error reading property ti,en-gpio-sleep: %d\n.", ret);
+ return NULL;
+ }
+
+
+ board_info->irq = client->irq;
+ board_info->irq_base = -1;
+ board_info->gpio_base = -1;
+
+ return board_info;
+}
+#else
+static inline
+struct tps65910_board *tps65910_parse_dt(struct i2c_client *client,
+ int *chip_id)
+{
+ return NULL;
+}
+#endif
+
+static __devinit int tps65910_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
{
struct tps65910 *tps65910;
struct tps65910_board *pmic_plat_data;
struct tps65910_platform_data *init_data;
int ret = 0;
+ int chip_id = id->driver_data;
pmic_plat_data = dev_get_platdata(&i2c->dev);
+
+ if (!pmic_plat_data && i2c->dev.of_node)
+ pmic_plat_data = tps65910_parse_dt(i2c, &chip_id);
+
if (!pmic_plat_data)
return -EINVAL;
- init_data = kzalloc(sizeof(struct tps65910_platform_data), GFP_KERNEL);
+ init_data = devm_kzalloc(&i2c->dev, sizeof(*init_data), GFP_KERNEL);
if (init_data == NULL)
return -ENOMEM;
- tps65910 = kzalloc(sizeof(struct tps65910), GFP_KERNEL);
- if (tps65910 == NULL) {
- kfree(init_data);
+ tps65910 = devm_kzalloc(&i2c->dev, sizeof(*tps65910), GFP_KERNEL);
+ if (tps65910 == NULL)
return -ENOMEM;
- }
i2c_set_clientdata(i2c, tps65910);
tps65910->dev = &i2c->dev;
tps65910->i2c_client = i2c;
- tps65910->id = id->driver_data;
- tps65910->read = tps65910_i2c_read;
- tps65910->write = tps65910_i2c_write;
+ tps65910->id = chip_id;
mutex_init(&tps65910->io_mutex);
- tps65910->regmap = regmap_init_i2c(i2c, &rc5t583_regmap_config);
+ tps65910->regmap = devm_regmap_init_i2c(i2c, &tps65910_regmap_config);
if (IS_ERR(tps65910->regmap)) {
ret = PTR_ERR(tps65910->regmap);
dev_err(&i2c->dev, "regmap initialization failed: %d\n", ret);
- goto regmap_err;
+ return ret;
}
ret = mfd_add_devices(tps65910->dev, -1,
tps65910s, ARRAY_SIZE(tps65910s),
NULL, 0);
- if (ret < 0)
- goto err;
+ if (ret < 0) {
+ dev_err(&i2c->dev, "mfd_add_devices failed: %d\n", ret);
+ return ret;
+ }
init_data->irq = pmic_plat_data->irq;
init_data->irq_base = pmic_plat_data->irq_base;
- tps65910_gpio_init(tps65910, pmic_plat_data->gpio_base);
-
tps65910_irq_init(tps65910, init_data->irq, init_data);
- kfree(init_data);
- return ret;
+ tps65910_sleepinit(tps65910, pmic_plat_data);
-err:
- regmap_exit(tps65910->regmap);
-regmap_err:
- kfree(tps65910);
- kfree(init_data);
return ret;
}
-static int tps65910_i2c_remove(struct i2c_client *i2c)
+static __devexit int tps65910_i2c_remove(struct i2c_client *i2c)
{
struct tps65910 *tps65910 = i2c_get_clientdata(i2c);
tps65910_irq_exit(tps65910);
mfd_remove_devices(tps65910->dev);
- regmap_exit(tps65910->regmap);
- kfree(tps65910);
return 0;
}
@@ -175,9 +282,10 @@ static struct i2c_driver tps65910_i2c_driver = {
.driver = {
.name = "tps65910",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(tps65910_of_match),
},
.probe = tps65910_i2c_probe,
- .remove = tps65910_i2c_remove,
+ .remove = __devexit_p(tps65910_i2c_remove),
.id_table = tps65910_i2c_id,
};
diff --git a/drivers/mfd/tps80031.c b/drivers/mfd/tps80031.c
index e8ea75c424c6..f0f2ce1f6840 100644
--- a/drivers/mfd/tps80031.c
+++ b/drivers/mfd/tps80031.c
@@ -105,6 +105,9 @@
#define TPS80031_CFG_INPUT_PUPD3 0xF2
#define TPS80031_CFG_INPUT_PUPD4 0xF3
+#define TPS80031_BBSPOR_CFG 0xE6
+#define TPS80031_BBSPOR_CHG_EN 0x8
+
struct tps80031_pupd_data {
u8 reg;
u8 pullup_bit;
@@ -568,6 +571,17 @@ static void tps80031_pupd_init(struct tps80031 *tps80031,
}
}
+static void tps80031_backup_battery_charger_control(struct tps80031 *tps80031,
+ int enable)
+{
+ if (enable)
+ tps80031_update(tps80031->dev, SLAVE_ID1, TPS80031_BBSPOR_CFG,
+ TPS80031_BBSPOR_CHG_EN, TPS80031_BBSPOR_CHG_EN);
+ else
+ tps80031_update(tps80031->dev, SLAVE_ID1, TPS80031_BBSPOR_CFG,
+ 0, TPS80031_BBSPOR_CHG_EN);
+}
+
static void tps80031_init_ext_control(struct tps80031 *tps80031,
struct tps80031_platform_data *pdata) {
int ret;
@@ -874,8 +888,22 @@ static irqreturn_t tps80031_irq(int irq, void *data)
acks = (tmp[2] << 16) | (tmp[1] << 8) | tmp[0];
if (acks) {
- ret = tps80031_writes(tps80031->dev, SLAVE_ID2,
- TPS80031_INT_STS_A, 3, tmp);
+ /*
+ * Hardware behavior: hardware have the shadow register for
+ * interrupt status register which is updated if interrupt
+ * comes just after the interrupt status read. This shadow
+ * register gets written to main status register and cleared
+ * if any byte write happens in any of status register like
+ * STS_A, STS_B or STS_C.
+ * Hence here to clear the original interrupt status and
+ * updating the STS register with the shadow register, it is
+ * require to write only one byte in any of STS register.
+ * Having multiple register write can cause the STS register
+ * to clear without handling those interrupt and can cause
+ * interrupt miss.
+ */
+ ret = tps80031_write(tps80031->dev, SLAVE_ID2,
+ TPS80031_INT_STS_A, 0);
if (ret < 0) {
dev_err(tps80031->dev, "failed to write "
"interrupt status\n");
@@ -1273,6 +1301,8 @@ static int __devinit tps80031_i2c_probe(struct i2c_client *client,
tps80031_debuginit(tps80031);
+ tps80031_backup_battery_charger_control(tps80031, 1);
+
if (pdata->use_power_off && !pm_power_off)
pm_power_off = tps80031_power_off;
@@ -1288,13 +1318,17 @@ fail:
#ifdef CONFIG_PM
static int tps80031_i2c_suspend(struct i2c_client *client, pm_message_t state)
{
+ struct tps80031 *tps80031 = i2c_get_clientdata(client);
if (client->irq)
disable_irq(client->irq);
+ tps80031_backup_battery_charger_control(tps80031, 0);
return 0;
}
static int tps80031_i2c_resume(struct i2c_client *client)
{
+ struct tps80031 *tps80031 = i2c_get_clientdata(client);
+ tps80031_backup_battery_charger_control(tps80031, 1);
if (client->irq)
enable_irq(client->irq);
return 0;
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 7b7e948ff4f5..dcf345e23487 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -562,6 +562,12 @@ config MAX1749_VIBRATOR
---help---
Adds a timed output vibrator device node for MAX1749 vibrator motor
+config THERM_EST
+ bool "Thermal estimator driver"
+ default n
+ ---help---
+ Thermal driver which estimates temperature based of other sensors.
+
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"
@@ -571,5 +577,6 @@ source "drivers/misc/lis3lv02d/Kconfig"
source "drivers/misc/carma/Kconfig"
source "drivers/misc/inv_mpu/Kconfig"
source "drivers/misc/tegra-baseband/Kconfig"
+source "drivers/misc/tegra-cec/Kconfig"
endif # MISC_DEVICES
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 5b3728ebcaee..d9172c99bf6d 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -57,4 +57,6 @@ obj-$(CONFIG_BCM4329_RFKILL) += bcm4329_rfkill.o
obj-$(CONFIG_INV_SENSORS) += inv_mpu/
obj-$(CONFIG_TEGRA_CRYPTO_DEV) += tegra-cryptodev.o
obj-$(CONFIG_TEGRA_BB_SUPPORT) += tegra-baseband/
+obj-$(CONFIG_TEGRA_CEC_SUPPORT) += tegra-cec/
obj-$(CONFIG_MAX1749_VIBRATOR) += max1749.o
+obj-$(CONFIG_THERM_EST) += therm_est.o
diff --git a/drivers/misc/bcm4329_rfkill.c b/drivers/misc/bcm4329_rfkill.c
index a077326f2553..9dc33fd51e59 100644
--- a/drivers/misc/bcm4329_rfkill.c
+++ b/drivers/misc/bcm4329_rfkill.c
@@ -44,6 +44,13 @@ static struct bcm4329_rfkill_data *bcm4329_rfkill;
static int bcm4329_bt_rfkill_set_power(void *data, bool blocked)
{
+ /*
+ * check if BT gpio_shutdown line status and current request are same.
+ * If same, then return, else perform requested operation.
+ */
+ if (gpio_get_value(bcm4329_rfkill->gpio_shutdown) && !blocked)
+ return 0;
+
if (blocked) {
if (bcm4329_rfkill->gpio_shutdown)
gpio_direction_output(bcm4329_rfkill->gpio_shutdown, 0);
@@ -104,7 +111,9 @@ static int bcm4329_rfkill_probe(struct platform_device *pdev)
ret = gpio_request(bcm4329_rfkill->gpio_reset,
"bcm4329_nreset_gpio");
} else {
- pr_warn("%s : can't find reset gpio.\n", __func__);
+ pr_warn("%s : can't find reset gpio. "
+ "reset gpio may not be defined for "
+ "this platform \n", __func__);
bcm4329_rfkill->gpio_reset = 0;
}
@@ -116,7 +125,9 @@ static int bcm4329_rfkill_probe(struct platform_device *pdev)
ret = gpio_request(bcm4329_rfkill->gpio_shutdown,
"bcm4329_nshutdown_gpio");
} else {
- pr_warn("%s : can't find shutdown gpio.\n", __func__);
+ pr_warn("%s : can't find shutdown gpio "
+ "shutdown gpio may not be defined for "
+ "this platform \n", __func__);
bcm4329_rfkill->gpio_shutdown = 0;
}
diff --git a/drivers/misc/nct1008.c b/drivers/misc/nct1008.c
index 56678a795497..a2714698d00d 100644
--- a/drivers/misc/nct1008.c
+++ b/drivers/misc/nct1008.c
@@ -3,7 +3,7 @@
*
* Driver for NCT1008, temperature monitoring device from ON Semiconductors
*
- * Copyright (c) 2010-2011, NVIDIA Corporation.
+ * Copyright (c) 2010-2012, 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
@@ -32,8 +32,6 @@
#include <linux/delay.h>
#include <linux/regulator/consumer.h>
-#define DRIVER_NAME "nct1008"
-
/* Register Addresses */
#define LOCAL_TEMP_RD 0x00
#define EXT_TEMP_RD_HI 0x01
@@ -94,7 +92,7 @@ static inline u8 temperature_to_value(bool extended, s8 temp)
return extended ? (u8)(temp + EXTENDED_RANGE_OFFSET) : (u8)temp;
}
-static int nct1008_get_temp(struct device *dev, long *pTemp)
+static int nct1008_get_temp(struct device *dev, long *etemp, long *itemp)
{
struct i2c_client *client = to_i2c_client(dev);
struct nct1008_platform_data *pdata = client->dev.platform_data;
@@ -106,30 +104,34 @@ static int nct1008_get_temp(struct device *dev, long *pTemp)
u8 value;
/* Read Local Temp */
- value = i2c_smbus_read_byte_data(client, LOCAL_TEMP_RD);
- if (value < 0)
- goto error;
- temp_local = value_to_temperature(pdata->ext_range, value);
- temp_local_milli = CELSIUS_TO_MILLICELSIUS(temp_local);
+ if (itemp) {
+ value = i2c_smbus_read_byte_data(client, LOCAL_TEMP_RD);
+ if (value < 0)
+ goto error;
+ temp_local = value_to_temperature(pdata->ext_range, value);
+ temp_local_milli = CELSIUS_TO_MILLICELSIUS(temp_local);
+
+ *itemp = temp_local_milli;
+ }
/* Read External Temp */
- value = i2c_smbus_read_byte_data(client, EXT_TEMP_RD_LO);
- if (value < 0)
- goto error;
- temp_ext_lo = (value >> 6);
+ if (etemp) {
+ value = i2c_smbus_read_byte_data(client, EXT_TEMP_RD_LO);
+ if (value < 0)
+ goto error;
+ temp_ext_lo = (value >> 6);
- value = i2c_smbus_read_byte_data(client, EXT_TEMP_RD_HI);
- if (value < 0)
- goto error;
- temp_ext_hi = value_to_temperature(pdata->ext_range, value);
+ value = i2c_smbus_read_byte_data(client, EXT_TEMP_RD_HI);
+ if (value < 0)
+ goto error;
+ temp_ext_hi = value_to_temperature(pdata->ext_range, value);
- temp_ext_milli = CELSIUS_TO_MILLICELSIUS(temp_ext_hi) +
- temp_ext_lo * 250;
+ temp_ext_milli = CELSIUS_TO_MILLICELSIUS(temp_ext_hi) +
+ temp_ext_lo * 250;
- /* Return max between Local and External Temp */
- *pTemp = max(temp_local_milli, temp_ext_milli);
+ *etemp = temp_ext_milli;
+ }
- dev_dbg(dev, "\n %s: ret temp=%ldC ", __func__, *pTemp);
return 0;
error:
dev_err(&client->dev, "\n error in file=: %s %s() line=%d: "
@@ -225,7 +227,7 @@ static ssize_t nct1008_set_temp_overheat(struct device *dev,
return -EINVAL;
}
/* check for system power down */
- err = nct1008_get_temp(dev, &currTemp);
+ err = nct1008_get_temp(dev, &currTemp, NULL);
if (err)
goto error;
@@ -403,7 +405,7 @@ static void print_reg(const char *reg_name, struct seq_file *s,
static int dbg_nct1008_show(struct seq_file *s, void *unused)
{
- seq_printf(s, "nct1008 Registers\n");
+ seq_printf(s, "nct1008 nct72 Registers\n");
seq_printf(s, "------------------\n");
print_reg("Local Temp Value ", s, 0x00);
print_reg("Ext Temp Value Hi ", s, 0x01);
@@ -442,8 +444,12 @@ static int __init nct1008_debuginit(struct nct1008_data *nct)
{
int err = 0;
struct dentry *d;
- d = debugfs_create_file("nct1008", S_IRUGO, NULL,
- (void *)nct, &debug_fops);
+ if (nct->chip == NCT72)
+ d = debugfs_create_file("nct72", S_IRUGO, NULL,
+ (void *)nct, &debug_fops);
+ else
+ d = debugfs_create_file("nct1008", S_IRUGO, NULL,
+ (void *)nct, &debug_fops);
if ((!d) || IS_ERR(d)) {
dev_err(&nct->client->dev, "Error: %s debugfs_create_file"
" returned an error\n", __func__);
@@ -563,12 +569,14 @@ static void nct1008_power_control(struct nct1008_data *data, bool is_enable)
ret = regulator_disable(data->nct_reg);
if (ret < 0)
- dev_err(&data->client->dev, "Error in %s rail vdd_nct1008, "
+ dev_err(&data->client->dev, "Error in %s rail vdd_nct%s, "
"error %d\n", (is_enable) ? "enabling" : "disabling",
+ (data->chip == NCT72) ? "72" : "1008",
ret);
else
- dev_info(&data->client->dev, "success in %s rail vdd_nct1008\n",
- (is_enable) ? "enabling" : "disabling");
+ dev_info(&data->client->dev, "success in %s rail vdd_nct%s\n",
+ (is_enable) ? "enabling" : "disabling",
+ (data->chip == NCT72) ? "72" : "1008");
}
static int __devinit nct1008_configure_sensor(struct nct1008_data* data)
@@ -692,7 +700,8 @@ error:
static int __devinit nct1008_configure_irq(struct nct1008_data *data)
{
- data->workqueue = create_singlethread_workqueue("nct1008");
+ data->workqueue = create_singlethread_workqueue((data->chip == NCT72) \
+ ? "nct72" : "nct1008");
INIT_WORK(&data->work, nct1008_work_func);
@@ -701,12 +710,18 @@ static int __devinit nct1008_configure_irq(struct nct1008_data *data)
else
return request_irq(data->client->irq, nct1008_irq,
IRQF_TRIGGER_LOW,
- DRIVER_NAME, data);
+ (data->chip == NCT72) ? "nct72" : "nct1008",
+ data);
}
int nct1008_thermal_get_temp(struct nct1008_data *data, long *temp)
{
- return nct1008_get_temp(&data->client->dev, temp);
+ return nct1008_get_temp(&data->client->dev, temp, NULL);
+}
+
+int nct1008_thermal_get_temps(struct nct1008_data *data, long *etemp, long *itemp)
+{
+ return nct1008_get_temp(&data->client->dev, etemp, itemp);
}
int nct1008_thermal_get_temp_low(struct nct1008_data *data, long *temp)
@@ -816,6 +831,7 @@ static int __devinit nct1008_probe(struct i2c_client *client,
return -ENOMEM;
data->client = client;
+ data->chip = id->driver_data;
memcpy(&data->plat_data, client->dev.platform_data,
sizeof(struct nct1008_platform_data));
i2c_set_clientdata(client, data);
@@ -911,14 +927,15 @@ static int nct1008_resume(struct i2c_client *client)
#endif
static const struct i2c_device_id nct1008_id[] = {
- { DRIVER_NAME, 0 },
- { }
+ { "nct1008", NCT1008 },
+ { "nct72", NCT72},
+ {}
};
MODULE_DEVICE_TABLE(i2c, nct1008_id);
static struct i2c_driver nct1008_driver = {
.driver = {
- .name = DRIVER_NAME,
+ .name = "nct1008_nct72",
},
.probe = nct1008_probe,
.remove = __devexit_p(nct1008_remove),
@@ -939,7 +956,7 @@ static void __exit nct1008_exit(void)
i2c_del_driver(&nct1008_driver);
}
-MODULE_DESCRIPTION("Temperature sensor driver for OnSemi NCT1008");
+MODULE_DESCRIPTION("Temperature sensor driver for OnSemi NCT1008/NCT72");
MODULE_LICENSE("GPL");
module_init(nct1008_init);
diff --git a/drivers/misc/tegra-baseband/Makefile b/drivers/misc/tegra-baseband/Makefile
index a95d84dbf117..68ec4fe83ac1 100644
--- a/drivers/misc/tegra-baseband/Makefile
+++ b/drivers/misc/tegra-baseband/Makefile
@@ -2,5 +2,7 @@
# Makefile for tegra baseband support.
#
+subdir-ccflags-y := -Werror
+
obj-$(CONFIG_TEGRA_BB_POWER) += bb-power.o
obj-$(CONFIG_TEGRA_BB_M7400) += bb-m7400.o
diff --git a/drivers/misc/tegra-baseband/bb-m7400.c b/drivers/misc/tegra-baseband/bb-m7400.c
index 5808a6e321cd..adabefdb100d 100644
--- a/drivers/misc/tegra-baseband/bb-m7400.c
+++ b/drivers/misc/tegra-baseband/bb-m7400.c
@@ -28,10 +28,12 @@
#include <linux/device.h>
#include <linux/usb.h>
#include <linux/wakelock.h>
+#include <linux/platform_data/tegra_usb.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <mach/tegra-bb-power.h>
#include <mach/usb_phy.h>
+
#include "bb-power.h"
static struct tegra_bb_gpio_data m7400_gpios[] = {
@@ -106,27 +108,26 @@ static void m7400_apdown_handshake(void)
gpio_set_value(gpio_awr, 0);
}
-static int m7400_l2_suspend(void)
+static void m7400_l2_suspend(void)
{
/* Gets called for two cases :
a) Port suspend.
b) Bus suspend. */
if (modem_status == BBSTATE_L2)
- return 0;
+ return;
/* Post bus suspend: Drive ARR low. */
gpio_set_value(gpio_arr, 0);
modem_status = BBSTATE_L2;
- return 0;
}
-static int m7400_l2_resume(void)
+static void m7400_l2_resume(void)
{
/* Gets called for two cases :
a) L2 resume.
b) bus resume phase of L3 resume. */
if (modem_status == BBSTATE_L0)
- return 0;
+ return;
/* Pre bus resume: Drive ARR high. */
gpio_set_value(gpio_arr, 1);
@@ -136,10 +137,9 @@ static int m7400_l2_resume(void)
if (gpio_wait_timeout(gpio_cwr, 1, 10) != 0) {
pr_info("%s: Error: timeout waiting for modem ack.\n",
__func__);
- return -1;
+ return;
}
modem_status = BBSTATE_L0;
- return 0;
}
static void m7400_l3_suspend(void)
@@ -193,20 +193,17 @@ static int m7400_power(int code)
static void m7400_ehci_customize(struct platform_device *pdev)
{
- struct tegra_ehci_platform_data *ehci_pdata;
- struct tegra_uhsic_config *hsic_config;
+ struct tegra_usb_platform_data *ehci_pdata;
- ehci_pdata = (struct tegra_ehci_platform_data *)
+ ehci_pdata = (struct tegra_usb_platform_data *)
pdev->dev.platform_data;
- hsic_config = (struct tegra_uhsic_config *)
- ehci_pdata->phy_config;
/* Register PHY callbacks */
- hsic_config->postsuspend = m7400_l2_suspend;
- hsic_config->preresume = m7400_l2_resume;
+ ehci_pdata->ops->post_suspend = m7400_l2_suspend;
+ ehci_pdata->ops->pre_resume = m7400_l2_resume;
/* Override required settings */
- ehci_pdata->power_down_on_bus_suspend = 0;
+ ehci_pdata->u_data.host.power_off_on_suspend = false;
}
static int m7400_attrib_write(struct device *dev, int value)
diff --git a/drivers/misc/tegra-cec/Kconfig b/drivers/misc/tegra-cec/Kconfig
new file mode 100644
index 000000000000..11fa9bc9ce17
--- /dev/null
+++ b/drivers/misc/tegra-cec/Kconfig
@@ -0,0 +1,19 @@
+menuconfig TEGRA_CEC_SUPPORT
+ bool "Tegra CEC support"
+ depends on ARCH_TEGRA
+ ---help---
+ Say Y here to get to see options for tegra CEC support.
+ This option alone does not add any kernel code.
+
+ If you say N, all options in this submenu will be skipped and disabled.
+
+if TEGRA_CEC_SUPPORT
+
+config TEGRA_CEC_T30
+ bool "Enable T30 CEC support"
+ ---help---
+ Adds HDMI-CEC driver for T30.
+
+ Disabled by default. Choose Y here if you want to build the driver.
+
+endif # TEGRA_CEC_SUPPORT
diff --git a/drivers/misc/tegra-cec/Makefile b/drivers/misc/tegra-cec/Makefile
new file mode 100644
index 000000000000..ab380305c35f
--- /dev/null
+++ b/drivers/misc/tegra-cec/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for tegra cec support.
+#
+
+obj-$(CONFIG_TEGRA_CEC_T30) += tegra_cec.o
diff --git a/drivers/misc/tegra-cec/tegra_cec.c b/drivers/misc/tegra-cec/tegra_cec.c
new file mode 100644
index 000000000000..a876d9d60712
--- /dev/null
+++ b/drivers/misc/tegra-cec/tegra_cec.c
@@ -0,0 +1,383 @@
+/*
+ * drivers/misc/tegra-cec/tegra_cec.c
+ *
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/ktime.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+
+#include <linux/platform_device.h>
+#include <linux/miscdevice.h>
+
+#include <mach/clk.h>
+
+#include "tegra_cec.h"
+
+
+int tegra_cec_open(struct inode *inode, struct file *file)
+{
+ struct miscdevice *miscdev = file->private_data;
+ struct tegra_cec *cec = container_of(miscdev,
+ struct tegra_cec, misc_dev);
+ dev_dbg(cec->dev, "%s\n", __func__);
+ file->private_data = cec;
+
+ return 0;
+}
+
+int tegra_cec_release(struct inode *inode, struct file *file)
+{
+ struct tegra_cec *cec = file->private_data;
+
+ dev_dbg(cec->dev, "%s\n", __func__);
+
+ return 0;
+}
+
+ssize_t tegra_cec_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ struct tegra_cec *cec = file->private_data;
+ unsigned long write_buff;
+
+ count = 4;
+
+ if (copy_from_user(&write_buff, buffer, count))
+ return -EFAULT;
+
+ writel((TEGRA_CEC_INT_MASK_TX_REGISTER_EMPTY |
+ TEGRA_CEC_INT_MASK_TX_REGISTER_UNDERRUN |
+ TEGRA_CEC_INT_MASK_TX_FRAME_OR_BLOCK_NAKD |
+ TEGRA_CEC_INT_MASK_TX_ARBITRATION_FAILED |
+ TEGRA_CEC_INT_MASK_TX_BUS_ANOMALY_DETECTED |
+ TEGRA_CEC_INT_MASK_RX_REGISTER_FULL |
+ TEGRA_CEC_INT_MASK_RX_REGISTER_OVERRUN),
+ cec->cec_base + TEGRA_CEC_INT_MASK);
+
+ wait_event_interruptible(cec->tx_waitq, cec->tx_wake == 1);
+ writel(write_buff, cec->cec_base + TEGRA_CEC_TX_REGISTER);
+ cec->tx_wake = 0;
+
+ writel((TEGRA_CEC_INT_MASK_TX_REGISTER_UNDERRUN |
+ TEGRA_CEC_INT_MASK_TX_FRAME_OR_BLOCK_NAKD |
+ TEGRA_CEC_INT_MASK_TX_ARBITRATION_FAILED |
+ TEGRA_CEC_INT_MASK_TX_BUS_ANOMALY_DETECTED |
+ TEGRA_CEC_INT_MASK_RX_REGISTER_FULL |
+ TEGRA_CEC_INT_MASK_RX_REGISTER_OVERRUN),
+ cec->cec_base + TEGRA_CEC_INT_MASK);
+
+ write_buff = 0x00;
+ return count;
+}
+
+ssize_t tegra_cec_read(struct file *file, char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ struct tegra_cec *cec = file->private_data;
+ unsigned short rx_buffer;
+ count = 2;
+
+ if (cec->rx_wake == 0)
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
+ wait_event_interruptible(cec->rx_waitq, cec->rx_wake == 1);
+
+ rx_buffer = readw(cec->cec_base + TEGRA_CEC_RX_REGISTER);
+
+ if (copy_to_user(buffer, &rx_buffer, count))
+ return -EFAULT;
+
+ rx_buffer = 0x0;
+ cec->rx_wake = 0;
+ return count;
+}
+
+static irqreturn_t tegra_cec_irq_handler(int irq, void *data)
+{
+ struct device *dev = data;
+ struct tegra_cec *cec = dev_get_drvdata(dev);
+ unsigned long status;
+
+ status = readl(cec->cec_base + TEGRA_CEC_INT_STAT);
+
+ if (!status)
+ return IRQ_HANDLED;
+
+ if ((status & TEGRA_CEC_INT_STAT_RX_REGISTER_OVERRUN) ||
+ (status & TEGRA_CEC_INT_STAT_RX_BUS_ANOMALY_DETECTED) ||
+ (status & TEGRA_CEC_INT_STAT_RX_START_BIT_DETECTED) ||
+ (status & TEGRA_CEC_INT_STAT_RX_BUS_ERROR_DETECTED)) {
+ writel((TEGRA_CEC_INT_STAT_RX_REGISTER_OVERRUN |
+ TEGRA_CEC_INT_STAT_RX_BUS_ANOMALY_DETECTED |
+ TEGRA_CEC_INT_STAT_RX_START_BIT_DETECTED |
+ TEGRA_CEC_INT_STAT_RX_BUS_ERROR_DETECTED),
+ cec->cec_base + TEGRA_CEC_INT_STAT);
+ } else if (status & TEGRA_CEC_INT_STAT_RX_REGISTER_FULL) {
+ writel((TEGRA_CEC_INT_STAT_RX_REGISTER_FULL),
+ cec->cec_base + TEGRA_CEC_INT_STAT);
+ cec->rx_wake = 1;
+ wake_up_interruptible(&cec->rx_waitq);
+ } else if ((status & TEGRA_CEC_INT_STAT_TX_REGISTER_UNDERRUN) ||
+ (status & TEGRA_CEC_INT_STAT_TX_FRAME_OR_BLOCK_NAKD) ||
+ (status & TEGRA_CEC_INT_STAT_TX_ARBITRATION_FAILED) ||
+ (status & TEGRA_CEC_INT_STAT_TX_BUS_ANOMALY_DETECTED)) {
+ writel((TEGRA_CEC_INT_STAT_TX_REGISTER_UNDERRUN |
+ TEGRA_CEC_INT_STAT_TX_FRAME_OR_BLOCK_NAKD |
+ TEGRA_CEC_INT_STAT_TX_REGISTER_EMPTY |
+ TEGRA_CEC_INT_STAT_TX_ARBITRATION_FAILED |
+ TEGRA_CEC_INT_STAT_TX_BUS_ANOMALY_DETECTED),
+ cec->cec_base + TEGRA_CEC_INT_STAT);
+ } else if (status & TEGRA_CEC_INT_STAT_TX_REGISTER_EMPTY) {
+ cec->tx_wake = 1;
+ wake_up_interruptible(&cec->tx_waitq);
+ writel((TEGRA_CEC_INT_STAT_TX_REGISTER_EMPTY),
+ cec->cec_base + TEGRA_CEC_INT_STAT);
+ } else if (status & TEGRA_CEC_INT_STAT_TX_FRAME_TRANSMITTED) {
+ writel((TEGRA_CEC_INT_STAT_TX_FRAME_TRANSMITTED),
+ cec->cec_base + TEGRA_CEC_INT_STAT);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static const struct file_operations tegra_cec_fops = {
+ .owner = THIS_MODULE,
+ .open = tegra_cec_open,
+ .release = tegra_cec_release,
+ .read = tegra_cec_read,
+ .write = tegra_cec_write,
+};
+
+static void tegra_cec_init(struct tegra_cec *cec)
+{
+
+ writel(0x00, cec->cec_base + TEGRA_CEC_HW_CONTROL);
+ writel(0x00, cec->cec_base + TEGRA_CEC_INT_MASK);
+ writel(0xffffffff, cec->cec_base + TEGRA_CEC_INT_STAT);
+ msleep(1000);
+
+ writel(0x00, cec->cec_base + TEGRA_CEC_SW_CONTROL);
+
+ writel((TEGRA_CEC_LOGICAL_ADDR<<TEGRA_CEC_HW_CONTROL_RX_LOGICAL_ADDRS_MASK)&
+ (~TEGRA_CEC_HW_CONTROL_RX_SNOOP) &
+ (~TEGRA_CEC_HW_CONTROL_RX_NAK_MODE) &
+ (~TEGRA_CEC_HW_CONTROL_TX_NAK_MODE) &
+ (~TEGRA_CEC_HW_CONTROL_FAST_SIM_MODE) |
+ (TEGRA_CEC_HW_CONTROL_TX_RX_MODE),
+ cec->cec_base + TEGRA_CEC_HW_CONTROL);
+
+ writel(0x00, cec->cec_base + TEGRA_CEC_INPUT_FILTER);
+
+ writel((0x7a << TEGRA_CEC_RX_TIMING_0_RX_START_BIT_MAX_LO_TIME_MASK) |
+ (0x6d << TEGRA_CEC_RX_TIMING_0_RX_START_BIT_MIN_LO_TIME_MASK) |
+ (0x93 << TEGRA_CEC_RX_TIMING_0_RX_START_BIT_MAX_DURATION_MASK) |
+ (0x86 << TEGRA_CEC_RX_TIMING_0_RX_START_BIT_MIN_DURATION_MASK),
+ cec->cec_base + TEGRA_CEC_RX_TIMING_0);
+
+ writel((0x35 << TEGRA_CEC_RX_TIMING_1_RX_DATA_BIT_MAX_LO_TIME_MASK) |
+ (0x21 << TEGRA_CEC_RX_TIMING_1_RX_DATA_BIT_SAMPLE_TIME_MASK) |
+ (0x56 << TEGRA_CEC_RX_TIMING_1_RX_DATA_BIT_MAX_DURATION_MASK) |
+ (0x40 << TEGRA_CEC_RX_TIMING_1_RX_DATA_BIT_MIN_DURATION_MASK),
+ cec->cec_base + TEGRA_CEC_RX_TIMING_1);
+
+ writel((0x50 << TEGRA_CEC_RX_TIMING_2_RX_END_OF_BLOCK_TIME_MASK),
+ cec->cec_base + TEGRA_CEC_RX_TIMING_2);
+
+ writel((0x74 << TEGRA_CEC_TX_TIMING_0_TX_START_BIT_LO_TIME_MASK) |
+ (0x8d << TEGRA_CEC_TX_TIMING_0_TX_START_BIT_DURATION_MASK) |
+ (0x08 << TEGRA_CEC_TX_TIMING_0_TX_BUS_XITION_TIME_MASK) |
+ (0x71 << TEGRA_CEC_TX_TIMING_0_TX_BUS_ERROR_LO_TIME_MASK),
+ cec->cec_base + TEGRA_CEC_TX_TIMING_0);
+
+ writel((0x2f << TEGRA_CEC_TX_TIMING_1_TX_LO_DATA_BIT_LO_TIME_MASK) |
+ (0x13 << TEGRA_CEC_TX_TIMING_1_TX_HI_DATA_BIT_LO_TIME_MASK) |
+ (0x4b << TEGRA_CEC_TX_TIMING_1_TX_DATA_BIT_DURATION_MASK) |
+ (0x21 << TEGRA_CEC_TX_TIMING_1_TX_ACK_NAK_BIT_SAMPLE_TIME_MASK),
+ cec->cec_base + TEGRA_CEC_TX_TIMING_1);
+
+ writel((0x07 << TEGRA_CEC_TX_TIMING_2_BUS_IDLE_TIME_ADDITIONAL_FRAME_MASK) |
+ (0x05 << TEGRA_CEC_TX_TIMING_2_TX_BUS_IDLE_TIME_NEW_FRAME_MASK) |
+ (0x03 << TEGRA_CEC_TX_TIMING_2_TX_BUS_IDLE_TIME_RETRY_FRAME_MASK),
+ cec->cec_base + TEGRA_CEC_TX_TIMING_2);
+
+ writel((TEGRA_CEC_INT_MASK_TX_REGISTER_UNDERRUN |
+ TEGRA_CEC_INT_MASK_TX_FRAME_OR_BLOCK_NAKD |
+ TEGRA_CEC_INT_MASK_TX_ARBITRATION_FAILED |
+ TEGRA_CEC_INT_MASK_TX_BUS_ANOMALY_DETECTED |
+ TEGRA_CEC_INT_MASK_RX_REGISTER_FULL |
+ TEGRA_CEC_INT_MASK_RX_REGISTER_OVERRUN),
+ cec->cec_base + TEGRA_CEC_INT_MASK);
+}
+
+static int __devinit tegra_cec_probe(struct platform_device *pdev)
+{
+ struct tegra_cec *cec;
+ struct resource *res;
+ int ret = 0;
+
+ cec = devm_kzalloc(&pdev->dev, sizeof(struct tegra_cec), GFP_KERNEL);
+
+ if (!cec)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ if (!res) {
+ dev_err(&pdev->dev,
+ "Unable to allocate resources for device.\n");
+ ret = -EBUSY;
+ goto cec_error;
+ }
+
+ if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res),
+ pdev->name)) {
+ dev_err(&pdev->dev,
+ "Unable to request mem region for device.\n");
+ ret = -EBUSY;
+ goto cec_error;
+ }
+
+ cec->tegra_cec_irq = platform_get_irq(pdev, 0);
+
+ if (cec->tegra_cec_irq <= 0) {
+ ret = -EBUSY;
+ goto cec_error;
+ }
+
+ cec->cec_base = devm_ioremap_nocache(&pdev->dev, res->start,
+ resource_size(res));
+
+ if (!cec->cec_base) {
+ dev_err(&pdev->dev, "Unable to grab IOs for device.\n");
+ ret = -EBUSY;
+ goto cec_error;
+ }
+
+ cec->clk = clk_get(&pdev->dev, "cec");
+
+ if (IS_ERR_OR_NULL(cec->clk)) {
+ dev_err(&pdev->dev, "can't get clock for CEC\n");
+ ret = -ENOENT;
+ goto clk_error;
+ }
+
+ clk_enable(cec->clk);
+
+ /* set context info. */
+ cec->dev = &pdev->dev;
+ cec->rx_wake = 0;
+ cec->tx_wake = 0;
+ init_waitqueue_head(&cec->rx_waitq);
+ init_waitqueue_head(&cec->tx_waitq);
+
+ platform_set_drvdata(pdev, cec);
+ /* clear out the hardware. */
+
+ tegra_cec_init(cec);
+
+ device_init_wakeup(&pdev->dev, 1);
+
+ cec->misc_dev.minor = MISC_DYNAMIC_MINOR;
+ cec->misc_dev.name = TEGRA_CEC_NAME;
+ cec->misc_dev.fops = &tegra_cec_fops;
+ cec->misc_dev.parent = &pdev->dev;
+
+ if (misc_register(&cec->misc_dev)) {
+ printk(KERN_WARNING "Couldn't register device , %s.\n", TEGRA_CEC_NAME);
+ goto cec_error;
+ }
+
+ ret = devm_request_irq(&pdev->dev, cec->tegra_cec_irq,
+ tegra_cec_irq_handler, IRQF_DISABLED, "cec_irq", &pdev->dev);
+
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Unable to request interrupt for device (err=%d).\n", ret);
+ goto cec_error;
+ }
+
+ dev_notice(&pdev->dev, "probed\n");
+
+ return 0;
+
+cec_error:
+ clk_disable(cec->clk)
+ clk_put(cec->clk);
+clk_error:
+ return ret;
+}
+
+static int tegra_cec_remove(struct platform_device *pdev)
+{
+ struct tegra_cec *cec = platform_get_drvdata(pdev);
+
+ clk_disable(cec->clk)
+ clk_put(cec->clk);
+
+ misc_deregister(&cec->misc_dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int tegra_cec_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct tegra_cec *cec = platform_get_drvdata(pdev);
+
+ clk_disable(cec->clk);
+
+ return 0;
+}
+
+static int tegra_cec_resume(struct platform_device *pdev)
+{
+
+ struct tegra_cec *cec = platform_get_drvdata(pdev);
+ clk_enable(cec->clk);
+ tegra_cec_init(cec);
+ return 0;
+}
+#endif
+
+static struct platform_driver tegra_cec_driver = {
+ .driver = {
+ .name = TEGRA_CEC_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = tegra_cec_probe,
+ .remove = tegra_cec_remove,
+
+#ifdef CONFIG_PM
+ .suspend = tegra_cec_suspend,
+ .resume = tegra_cec_resume,
+#endif
+};
+
+module_platform_driver(tegra_cec_driver);
diff --git a/drivers/misc/tegra-cec/tegra_cec.h b/drivers/misc/tegra-cec/tegra_cec.h
new file mode 100644
index 000000000000..acc94dc61965
--- /dev/null
+++ b/drivers/misc/tegra-cec/tegra_cec.h
@@ -0,0 +1,134 @@
+/*
+ * drivers/misc/tegra-cec/tegra_cec.h
+ *
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/pm.h>
+
+
+struct tegra_cec {
+ struct device *dev;
+ struct miscdevice misc_dev;
+ struct clk *clk;
+ void __iomem *cec_base;
+ int tegra_cec_irq;
+ wait_queue_head_t rx_waitq;
+ wait_queue_head_t tx_waitq;
+ unsigned int rx_wake;
+ unsigned int tx_wake;
+};
+static int tegra_cec_remove(struct platform_device *pdev);
+
+/*CEC Timing registers*/
+#define TEGRA_CEC_SW_CONTROL 0X000
+#define TEGRA_CEC_HW_CONTROL 0X004
+#define TEGRA_CEC_INPUT_FILTER 0X008
+#define TEGRA_CEC_TX_REGISTER 0X010
+#define TEGRA_CEC_RX_REGISTER 0X014
+#define TEGRA_CEC_RX_TIMING_0 0X018
+#define TEGRA_CEC_RX_TIMING_1 0X01C
+#define TEGRA_CEC_RX_TIMING_2 0X020
+#define TEGRA_CEC_TX_TIMING_0 0X024
+#define TEGRA_CEC_TX_TIMING_1 0X028
+#define TEGRA_CEC_TX_TIMING_2 0X02C
+#define TEGRA_CEC_INT_STAT 0X030
+#define TEGRA_CEC_INT_MASK 0X034
+#define TEGRA_CEC_HW_DEBUG_RX 0X038
+#define TEGRA_CEC_HW_DEBUG_TX 0X03C
+
+#define TEGRA_CEC_LOGICAL_ADDR 0x10
+
+#define TEGRA_CEC_HW_CONTROL_RX_LOGICAL_ADDRS_MASK 0
+#define TEGRA_CEC_HW_CONTROL_RX_SNOOP (1<<15)
+#define TEGRA_CEC_HW_CONTROL_RX_NAK_MODE (1<<16)
+#define TEGRA_CEC_HW_CONTROL_TX_NAK_MODE (1<<24)
+#define TEGRA_CEC_HW_CONTROL_FAST_SIM_MODE (1<<30)
+#define TEGRA_CEC_HW_CONTROL_TX_RX_MODE (1<<31)
+
+#define TEGRA_CEC_INPUT_FILTER_MODE (1<<31)
+#define TEGRA_CEC_INPUT_FILTER_FIFO_LENGTH_MASK 0
+
+#define TEGRA_CEC_TX_REGISTER_DATA_MASK 0
+#define TEGRA_CEC_TX_REGISTER_EOM_MASK 8
+#define TEGRA_CEC_TX_REGISTER_ADDRESS_MODE_MASK 12
+#define TEGRA_CEC_TX_REGISTER_GENERATE_START_BIT_MASK 16
+#define TEGRA_CEC_TX_REGISTER_RETRY_FRAME_MASK 17
+
+#define TEGRA_CEC_RX_REGISTER_MASK 0
+#define TEGRA_CEC_RX_REGISTER_EOM (1<<8)
+#define TEGRA_CEC_RX_REGISTER_ACK (1<<9)
+
+#define TEGRA_CEC_RX_TIMING_0_RX_START_BIT_MAX_LO_TIME_MASK 0
+#define TEGRA_CEC_RX_TIMING_0_RX_START_BIT_MIN_LO_TIME_MASK 8
+#define TEGRA_CEC_RX_TIMING_0_RX_START_BIT_MAX_DURATION_MASK 16
+#define TEGRA_CEC_RX_TIMING_0_RX_START_BIT_MIN_DURATION_MASK 24
+
+#define TEGRA_CEC_RX_TIMING_1_RX_DATA_BIT_MAX_LO_TIME_MASK 0
+#define TEGRA_CEC_RX_TIMING_1_RX_DATA_BIT_SAMPLE_TIME_MASK 8
+#define TEGRA_CEC_RX_TIMING_1_RX_DATA_BIT_MAX_DURATION_MASK 16
+#define TEGRA_CEC_RX_TIMING_1_RX_DATA_BIT_MIN_DURATION_MASK 24
+
+#define TEGRA_CEC_RX_TIMING_2_RX_END_OF_BLOCK_TIME_MASK 0
+
+#define TEGRA_CEC_TX_TIMING_0_TX_START_BIT_LO_TIME_MASK 0
+#define TEGRA_CEC_TX_TIMING_0_TX_START_BIT_DURATION_MASK 8
+#define TEGRA_CEC_TX_TIMING_0_TX_BUS_XITION_TIME_MASK 16
+#define TEGRA_CEC_TX_TIMING_0_TX_BUS_ERROR_LO_TIME_MASK 24
+
+#define TEGRA_CEC_TX_TIMING_1_TX_LO_DATA_BIT_LO_TIME_MASK 0
+#define TEGRA_CEC_TX_TIMING_1_TX_HI_DATA_BIT_LO_TIME_MASK 8
+#define TEGRA_CEC_TX_TIMING_1_TX_DATA_BIT_DURATION_MASK 16
+#define TEGRA_CEC_TX_TIMING_1_TX_ACK_NAK_BIT_SAMPLE_TIME_MASK 24
+
+#define TEGRA_CEC_TX_TIMING_2_BUS_IDLE_TIME_ADDITIONAL_FRAME_MASK 0
+#define TEGRA_CEC_TX_TIMING_2_TX_BUS_IDLE_TIME_NEW_FRAME_MASK 4
+#define TEGRA_CEC_TX_TIMING_2_TX_BUS_IDLE_TIME_RETRY_FRAME_MASK 8
+
+#define TEGRA_CEC_INT_STAT_TX_REGISTER_EMPTY (1<<0)
+#define TEGRA_CEC_INT_STAT_TX_REGISTER_UNDERRUN (1<<1)
+#define TEGRA_CEC_INT_STAT_TX_FRAME_OR_BLOCK_NAKD (1<<2)
+#define TEGRA_CEC_INT_STAT_TX_ARBITRATION_FAILED (1<<3)
+#define TEGRA_CEC_INT_STAT_TX_BUS_ANOMALY_DETECTED (1<<4)
+#define TEGRA_CEC_INT_STAT_TX_FRAME_TRANSMITTED (1<<5)
+#define TEGRA_CEC_INT_STAT_RX_REGISTER_FULL (1<<8)
+#define TEGRA_CEC_INT_STAT_RX_REGISTER_OVERRUN (1<<9)
+#define TEGRA_CEC_INT_STAT_RX_START_BIT_DETECTED (1<<10)
+#define TEGRA_CEC_INT_STAT_RX_BUS_ANOMALY_DETECTED (1<<11)
+#define TEGRA_CEC_INT_STAT_RX_BUS_ERROR_DETECTED (1<<12)
+#define TEGRA_CEC_INT_STAT_FILTERED_RX_DATA_PIN_TRANSITION_H2L (1<<13)
+#define TEGRA_CEC_INT_STAT_FILTERED_RX_DATA_PIN_TRANSITION_L2H (1<<14)
+
+#define TEGRA_CEC_INT_MASK_TX_REGISTER_EMPTY (1<<0)
+#define TEGRA_CEC_INT_MASK_TX_REGISTER_UNDERRUN (1<<1)
+#define TEGRA_CEC_INT_MASK_TX_FRAME_OR_BLOCK_NAKD (1<<2)
+#define TEGRA_CEC_INT_MASK_TX_ARBITRATION_FAILED (1<<3)
+#define TEGRA_CEC_INT_MASK_TX_BUS_ANOMALY_DETECTED (1<<4)
+#define TEGRA_CEC_INT_MASK_TX_FRAME_TRANSMITTED (1<<5)
+#define TEGRA_CEC_INT_MASK_RX_REGISTER_FULL (1<<8)
+#define TEGRA_CEC_INT_MASK_RX_REGISTER_OVERRUN (1<<9)
+#define TEGRA_CEC_INT_MASK_RX_START_BIT_DETECTED (1<<10)
+#define TEGRA_CEC_INT_MASK_RX_BUS_ANOMALY_DETECTED (1<<11)
+#define TEGRA_CEC_INT_MASK_RX_BUS_ERROR_DETECTED (1<<12)
+#define TEGRA_CEC_INT_MASK_FILTERED_RX_DATA_PIN_TRANSITION_H2L (1<<13)
+#define TEGRA_CEC_INT_MASK_FILTERED_RX_DATA_PIN_TRANSITION_L2H (1<<14)
+
+#define TEGRA_CEC_HW_DEBUG_TX_DURATION_COUNT_MASK 0
+#define TEGRA_CEC_HW_DEBUG_TX_TXBIT_COUNT_MASK 17
+#define TEGRA_CEC_HW_DEBUG_TX_STATE_MASK 21
+#define TEGRA_CEC_HW_DEBUG_TX_FORCELOOUT (1<<25)
+#define TEGRA_CEC_HW_DEBUG_TX_TXDATABIT_SAMPLE_TIMER (1<<26)
+
+#define TEGRA_CEC_NAME "tegra_cec"
diff --git a/drivers/misc/therm_est.c b/drivers/misc/therm_est.c
new file mode 100644
index 000000000000..e67fc664c7af
--- /dev/null
+++ b/drivers/misc/therm_est.c
@@ -0,0 +1,139 @@
+/*
+ * drivers/misc/therm_est.c
+ *
+ * Copyright (C) 2010-2012 NVIDIA Corporation.
+ *
+ * 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/cpufreq.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/syscalls.h>
+#include <linux/therm_est.h>
+
+int therm_est_get_temp(struct therm_estimator *est, long *temp)
+{
+ *temp = est->cur_temp;
+ return 0;
+}
+
+int therm_est_set_limits(struct therm_estimator *est,
+ long lo_limit,
+ long hi_limit)
+{
+ est->therm_est_lo_limit = lo_limit;
+ est->therm_est_hi_limit = hi_limit;
+ return 0;
+}
+
+int therm_est_set_alert(struct therm_estimator *est,
+ void (*cb)(void *),
+ void *cb_data)
+{
+ if ((!cb) || est->callback)
+ BUG();
+
+ est->callback = cb;
+ est->callback_data = cb_data;
+
+ return 0;
+}
+
+static void therm_est_work_func(struct work_struct *work)
+{
+ int i, j, index, sum = 0;
+ long temp;
+ struct delayed_work *dwork = container_of (work,
+ struct delayed_work, work);
+ struct therm_estimator *est = container_of(
+ dwork,
+ struct therm_estimator,
+ therm_est_work);
+
+ for (i = 0; i < est->ndevs; i++) {
+ if (est->devs[i]->get_temp(est->devs[i]->dev_data, &temp))
+ continue;
+ est->devs[i]->hist[(est->ntemp % HIST_LEN)] = temp;
+ }
+
+ for (i = 0; i < est->ndevs; i++) {
+ for (j = 0; j < HIST_LEN; j++) {
+ index = (est->ntemp - j + HIST_LEN) % HIST_LEN;
+ sum += est->devs[i]->hist[index] *
+ est->devs[i]->coeffs[j];
+ }
+ }
+
+ est->cur_temp = sum / 100 + est->toffset;
+
+ est->ntemp++;
+
+ if (est->callback && ((est->cur_temp >= est->therm_est_hi_limit) ||
+ (est->cur_temp <= est->therm_est_lo_limit)))
+ est->callback(est->callback_data);
+
+ queue_delayed_work(est->workqueue, &est->therm_est_work,
+ msecs_to_jiffies(est->polling_period));
+}
+
+struct therm_estimator *therm_est_register(
+ struct therm_est_subdevice **devs,
+ int ndevs,
+ long toffset,
+ long polling_period)
+{
+ int i, j;
+ long temp;
+ struct therm_estimator *est;
+ struct therm_est_subdevice *dev;
+
+ est = kzalloc(sizeof(struct therm_estimator), GFP_KERNEL);
+ if (IS_ERR_OR_NULL(est))
+ return ERR_PTR(-ENOMEM);
+
+ est->devs = devs;
+ est->ndevs = ndevs;
+ est->toffset = toffset;
+ est->polling_period = polling_period;
+
+ /* initialize history */
+ for (i = 0; i < ndevs; i++) {
+ dev = est->devs[i];
+
+ if (dev->get_temp(dev->dev_data, &temp)) {
+ kfree(est);
+ return ERR_PTR(-EINVAL);
+ }
+
+ for (j = 0; j < HIST_LEN; j++) {
+ dev->hist[j] = temp;
+ }
+ }
+
+ est->workqueue = alloc_workqueue("therm_est",
+ WQ_HIGHPRI | WQ_UNBOUND | WQ_RESCUER, 1);
+ INIT_DELAYED_WORK(&est->therm_est_work, therm_est_work_func);
+
+ queue_delayed_work(est->workqueue,
+ &est->therm_est_work,
+ msecs_to_jiffies(est->polling_period));
+
+ return est;
+}
diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig
index ebb4afe6c702..3875c21e04fa 100644
--- a/drivers/mmc/card/Kconfig
+++ b/drivers/mmc/card/Kconfig
@@ -76,3 +76,13 @@ config MMC_TEST
This driver is only of interest to those developing or
testing a host driver. Most people should say N here.
+
+config MMC_BKOPS
+ bool "Enable background ops"
+ default n
+ help
+ Say Y here to enable background ops in driver. This will result
+ in issuing of MMC_SWITCH command to write byte 164 of EXT_CSD,
+ in order to trigger background ops in the MMC device's
+ firmware, whenever URGENT_BKOPS flag is found to be set in a
+ read/write command's response.
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 2bd93d7a5170..bd5427d1f9e3 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -59,8 +59,6 @@ MODULE_ALIAS("mmc:block");
#define INAND_CMD38_ARG_SECTRIM1 0x81
#define INAND_CMD38_ARG_SECTRIM2 0x88
-#define MMC_CMD_RETRIES 10
-
static DEFINE_MUTEX(block_mutex);
/*
@@ -945,7 +943,6 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
if (!mmc_card_blockaddr(card))
brq->cmd.arg <<= 9;
brq->cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
- brq->cmd.retries = MMC_CMD_RETRIES;
brq->data.blksz = 512;
brq->stop.opcode = MMC_STOP_TRANSMISSION;
brq->stop.arg = 0;
diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c
index 440b97d9e44b..86817085aec7 100644
--- a/drivers/mmc/card/mmc_test.c
+++ b/drivers/mmc/card/mmc_test.c
@@ -211,7 +211,7 @@ static struct mmc_test_parameter mmc_test_parameter[] = {
static long mmc_test_set_testcase(struct mmc_test_card *test)
{
- return 0;
+ return mmc_test_parameter[0].value;
}
static long mmc_test_set_clock(struct mmc_test_card *test)
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 2a288e936a84..35f3df8810e0 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -109,11 +109,6 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
cmd->retries--;
cmd->error = 0;
- if (mrq->data) {
- mrq->data->error = 0;
- if (mrq->stop)
- mrq->stop->error = 0;
- }
host->ops->request(host, mrq);
} else {
led_trigger_event(host->led, LED_OFF);
@@ -277,13 +272,44 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,
{
int err = 0;
struct mmc_async_req *data = host->areq;
+ struct mmc_card *card = host->card;
+ struct timeval before_time, after_time;
/* Prepare a new request */
if (areq)
mmc_pre_req(host, areq->mrq, !host->areq);
if (host->areq) {
+ if (card->ext_csd.refresh &&
+ (host->areq->mrq->data->flags & MMC_DATA_WRITE))
+ do_gettimeofday(&before_time);
mmc_wait_for_req_done(host, host->areq->mrq);
+ if (card->ext_csd.refresh &&
+ (host->areq->mrq->data->flags & MMC_DATA_WRITE)) {
+ do_gettimeofday(&after_time);
+ switch (after_time.tv_sec - before_time.tv_sec) {
+ case 0:
+ if (after_time.tv_usec -
+ before_time.tv_usec >=
+ MMC_SLOW_WRITE_TIME) {
+ card->ext_csd.last_tv_sec =
+ after_time.tv_sec;
+ card->ext_csd.last_bkops_tv_sec =
+ after_time.tv_sec;
+ }
+ break;
+ case 1:
+ if (after_time.tv_usec -
+ before_time.tv_usec <
+ MMC_SLOW_WRITE_TIME - 1000000)
+ break;
+ default:
+ card->ext_csd.last_tv_sec =
+ after_time.tv_sec;
+ card->ext_csd.last_bkops_tv_sec =
+ after_time.tv_sec;
+ }
+ }
err = host->areq->err_check(host->card, host->areq);
if (err) {
mmc_post_req(host, host->areq->mrq, 0);
@@ -336,6 +362,7 @@ int mmc_bkops_start(struct mmc_card *card, bool is_synchronous)
{
int err;
unsigned long flags;
+ struct timeval before_time, after_time;
BUG_ON(!card);
@@ -343,10 +370,29 @@ int mmc_bkops_start(struct mmc_card *card, bool is_synchronous)
return 1;
mmc_claim_host(card->host);
+ if (card->ext_csd.refresh)
+ do_gettimeofday(&before_time);
err = mmc_send_bk_ops_cmd(card, is_synchronous);
if (err)
pr_err("%s: abort bk ops (%d error)\n",
mmc_hostname(card->host), err);
+ if (card->ext_csd.refresh) {
+ do_gettimeofday(&after_time);
+ switch (after_time.tv_sec - before_time.tv_sec) {
+ case 0:
+ if (after_time.tv_usec - before_time.tv_usec >=
+ MMC_SLOW_WRITE_TIME)
+ card->ext_csd.last_tv_sec = after_time.tv_sec;
+ break;
+ case 1:
+ if (after_time.tv_usec - before_time.tv_usec <
+ MMC_SLOW_WRITE_TIME - 1000000)
+ break;
+ default:
+ card->ext_csd.last_tv_sec = after_time.tv_sec;
+ }
+ card->ext_csd.last_bkops_tv_sec = after_time.tv_sec;
+ }
/*
* Incase of asynchronous backops, set card state
@@ -365,6 +411,57 @@ int mmc_bkops_start(struct mmc_card *card, bool is_synchronous)
}
EXPORT_SYMBOL(mmc_bkops_start);
+static void mmc_bkops_work(struct work_struct *work)
+{
+ struct mmc_card *card = container_of(work, struct mmc_card, bkops);
+ mmc_bkops_start(card, true);
+}
+
+static void mmc_refresh_work(struct work_struct *work)
+{
+ struct mmc_card *card = container_of(work, struct mmc_card, refresh);
+ char buf[512];
+ mmc_gen_cmd(card, buf, 0x44, 0x1, 0x0, 0x1);
+}
+
+void mmc_refresh(unsigned long data)
+{
+ struct mmc_card *card = (struct mmc_card *) data;
+ struct timeval cur_time;
+ __kernel_time_t timeout, timeout1, timeout2;
+
+ if ((!card) || (!card->ext_csd.refresh))
+ return;
+
+ INIT_WORK(&card->bkops, (work_func_t) mmc_bkops_work);
+ INIT_WORK(&card->refresh, (work_func_t) mmc_refresh_work);
+
+ do_gettimeofday(&cur_time);
+ timeout1 = MMC_REFRESH_INTERVAL - (cur_time.tv_sec -
+ card->ext_csd.last_tv_sec);
+ if ((cur_time.tv_sec < card->ext_csd.last_tv_sec) ||
+ (timeout1 <= 0)) {
+ queue_work(workqueue, &card->refresh);
+ card->ext_csd.last_tv_sec = cur_time.tv_sec;
+ card->ext_csd.last_bkops_tv_sec = cur_time.tv_sec;
+ timeout1 = MMC_REFRESH_INTERVAL;
+ }
+
+ timeout2 = MMC_BKOPS_INTERVAL - (cur_time.tv_sec -
+ card->ext_csd.last_bkops_tv_sec);
+ if ((cur_time.tv_sec < card->ext_csd.last_bkops_tv_sec) ||
+ (timeout2 <= 0)) {
+ mmc_card_set_need_bkops(card);
+ queue_work(workqueue, &card->bkops);
+ timeout2 = MMC_BKOPS_INTERVAL;
+ }
+
+ timeout = timeout1 < timeout2 ? timeout1 : timeout2;
+ card->timer.expires = jiffies + timeout*HZ;
+ add_timer(&card->timer);
+}
+EXPORT_SYMBOL(mmc_refresh);
+
/**
* mmc_interrupt_hpi - Issue for High priority Interrupt
* @card: the MMC card associated with the HPI transfer
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 69fb2275845c..40c93b3dccd7 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -96,6 +96,7 @@ static int mmc_decode_cid(struct mmc_card *card)
card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8);
card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8);
card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8);
+ card->cid.prod_rev = UNSTUFF_BITS(resp, 48, 8);
card->cid.serial = UNSTUFF_BITS(resp, 16, 32);
card->cid.month = UNSTUFF_BITS(resp, 12, 4);
card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997;
@@ -425,6 +426,11 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
/* Check whether the eMMC card supports background ops */
if (ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)
card->ext_csd.bk_ops = 1;
+
+ /* Check whether the eMMC card needs proactive refresh */
+ if ((card->cid.manfid == 0x90) && ((card->cid.prod_rev == 0x73)
+ || (card->cid.prod_rev == 0x7b)))
+ card->ext_csd.refresh = 1;
}
if (ext_csd[EXT_CSD_ERASED_MEM_CONT])
@@ -516,6 +522,7 @@ MMC_DEV_ATTR(hwrev, "0x%x\n", card->cid.hwrev);
MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid);
MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name);
MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid);
+MMC_DEV_ATTR(prv, "0x%x\n", card->cid.prod_rev);
MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial);
MMC_DEV_ATTR(enhanced_area_offset, "%llu\n",
card->ext_csd.enhanced_area_offset);
@@ -532,6 +539,7 @@ static struct attribute *mmc_std_attrs[] = {
&dev_attr_manfid.attr,
&dev_attr_name.attr,
&dev_attr_oemid.attr,
+ &dev_attr_prv.attr,
&dev_attr_serial.attr,
&dev_attr_enhanced_area_offset.attr,
&dev_attr_enhanced_area_size.attr,
@@ -672,6 +680,17 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
if (err)
goto free_card;
+ if (card->ext_csd.refresh) {
+ init_timer(&card->timer);
+ card->timer.data = (unsigned long) card;
+ card->timer.function = mmc_refresh;
+ card->timer.expires = MMC_BKOPS_INTERVAL <
+ MMC_REFRESH_INTERVAL ? MMC_BKOPS_INTERVAL :
+ MMC_REFRESH_INTERVAL;
+ card->timer.expires *= HZ;
+ card->timer.expires += jiffies;
+ add_timer(&card->timer);
+ }
/* If doing byte addressing, check if required to do sector
* addressing. Handle the case of <2GB cards needing sector
* addressing. See section 8.1 JEDEC Standard JED84-A441;
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 330b968393d6..c85c58aca3e2 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -588,7 +588,7 @@ int mmc_send_bk_ops_cmd(struct mmc_card *card, bool is_synchronous)
cmd.opcode = MMC_SWITCH;
cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
- (EXT_CSD_BKOPS_EN << 16) |
+ (EXT_CSD_BKOPS_START << 16) |
(1 << 8) |
EXT_CSD_CMD_SET_NORMAL;
if (is_synchronous)
@@ -617,3 +617,66 @@ int mmc_send_bk_ops_cmd(struct mmc_card *card, bool is_synchronous)
return 0;
}
+
+int mmc_gen_cmd(struct mmc_card *card, void *buf, u8 index, u8 arg1, u8 arg2, u8 mode)
+{
+ struct mmc_request mrq;
+ struct mmc_command cmd;
+ struct mmc_data data;
+ struct mmc_command stop;
+ struct scatterlist sg;
+ void *data_buf;
+
+ mmc_set_blocklen(card, 512);
+
+ data_buf = kmalloc(512, GFP_KERNEL);
+ if (data_buf == NULL)
+ return -ENOMEM;
+
+ memset(&mrq, 0, sizeof(struct mmc_request));
+ memset(&cmd, 0, sizeof(struct mmc_command));
+ memset(&data, 0, sizeof(struct mmc_data));
+ memset(&stop, 0, sizeof(struct mmc_command));
+
+ mrq.cmd = &cmd;
+ mrq.data = &data;
+ mrq.stop = &stop;
+
+ cmd.opcode = MMC_GEN_CMD;
+ cmd.arg = (arg2 << 16) |
+ (arg1 << 8) |
+ (index << 1) |
+ mode;
+
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+
+ data.blksz = 512;
+ data.blocks = 1;
+ data.flags = MMC_DATA_READ;
+ data.sg = &sg;
+ data.sg_len = 1;
+
+ stop.opcode = MMC_STOP_TRANSMISSION;
+ stop.arg = 0;
+ stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+
+ sg_init_one(&sg, data_buf, 512);
+
+ mmc_set_data_timeout(&data, card);
+
+ mmc_claim_host(card->host);
+ mmc_wait_for_req(card->host, &mrq);
+ mmc_release_host(card->host);
+
+ memcpy(buf, data_buf, 512);
+ kfree(data_buf);
+
+ if (cmd.error)
+ return cmd.error;
+ if (data.error)
+ return data.error;
+ if (stop.error)
+ return stop.error;
+
+ return 0;
+}
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
index d8f157dee147..a453531b46b6 100644
--- a/drivers/mmc/core/mmc_ops.h
+++ b/drivers/mmc/core/mmc_ops.h
@@ -29,6 +29,7 @@ int mmc_card_sleepawake(struct mmc_host *host, int sleep);
int mmc_bus_test(struct mmc_card *card, u8 bus_width);
int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status);
int mmc_send_bk_ops_cmd(struct mmc_card *card, bool is_synchronous);
+int mmc_gen_cmd(struct mmc_card *card, void *buf, u8 index, u8 arg1, u8 arg2, u8 mode);
#endif
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index d6ed03d4f22a..609fd6391d1f 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -112,9 +112,13 @@ struct tegra_sdhci_host {
unsigned int vddio_max_uv;
/* max clk supported by the platform */
unsigned int max_clk_limit;
+ /* max ddr clk supported by the platform */
+ unsigned int ddr_clk_limit;
struct tegra_io_dpd *dpd;
bool card_present;
bool is_rail_enabled;
+ struct clk *emc_clk;
+ unsigned int emc_max_clk;
};
static u32 tegra_sdhci_readl(struct sdhci_host *host, int reg)
@@ -366,14 +370,30 @@ static void tegra_sdhci_set_clk_rate(struct sdhci_host *sdhci,
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci);
struct tegra_sdhci_host *tegra_host = pltfm_host->priv;
unsigned int clk_rate;
+ unsigned int emc_clk;
+ /*
+ * In SDR50 mode, run the sdmmc controller at freq greater than
+ * 104MHz to ensure the core voltage is at 1.2V. If the core voltage
+ * is below 1.2V, CRC errors would occur during data transfers.
+ */
if (sdhci->mmc->card &&
- mmc_card_ddr_mode(sdhci->mmc->card)) {
+ (mmc_card_ddr_mode(sdhci->mmc->card) ||
+ (sdhci->mmc->ios.timing == MMC_TIMING_UHS_SDR50))) {
/*
* In ddr mode, tegra sdmmc controller clock frequency
* should be double the card clock frequency.
*/
- clk_rate = clock * 2;
+ if (tegra_host->ddr_clk_limit) {
+ clk_rate = tegra_host->ddr_clk_limit * 2;
+ if (tegra_host->emc_clk) {
+ emc_clk = clk_get_rate(tegra_host->emc_clk);
+ if (emc_clk == tegra_host->emc_max_clk)
+ clk_rate = clock * 2;
+ }
+ } else {
+ clk_rate = clock * 2;
+ }
} else {
if (clock <= tegra_sdhost_min_freq)
clk_rate = tegra_sdhost_min_freq;
@@ -381,15 +401,6 @@ static void tegra_sdhci_set_clk_rate(struct sdhci_host *sdhci,
clk_rate = tegra_sdhost_std_freq;
else
clk_rate = clock;
-
- /*
- * In SDR50 mode, run the sdmmc controller at 208MHz to ensure
- * the core voltage is at 1.2V. If the core voltage is below 1.2V, CRC
- * errors would occur during data transfers.
- */
- if ((sdhci->mmc->ios.timing == MMC_TIMING_UHS_SDR50) &&
- (clk_rate == tegra_sdhost_std_freq))
- clk_rate <<= 1;
}
if (tegra_host->max_clk_limit &&
@@ -534,11 +545,6 @@ static int tegra_sdhci_signal_voltage_switch(struct sdhci_host *sdhci,
u16 clk, ctrl;
unsigned int val;
- /* Switch OFF the card clock to prevent glitches on the clock line */
- clk = sdhci_readw(sdhci, SDHCI_CLOCK_CONTROL);
- clk &= ~SDHCI_CLOCK_CARD_EN;
- sdhci_writew(sdhci, clk, SDHCI_CLOCK_CONTROL);
-
ctrl = sdhci_readw(sdhci, SDHCI_HOST_CONTROL2);
if (signal_voltage == MMC_SIGNAL_VOLTAGE_180) {
ctrl |= SDHCI_CTRL_VDD_180;
@@ -548,6 +554,17 @@ static int tegra_sdhci_signal_voltage_switch(struct sdhci_host *sdhci,
if (ctrl & SDHCI_CTRL_VDD_180)
ctrl &= ~SDHCI_CTRL_VDD_180;
}
+
+ /* Check if the slot can support the required voltage */
+ if (min_uV > tegra_host->vddio_max_uv)
+ return 0;
+
+ /* Switch OFF the card clock to prevent glitches on the clock line */
+ clk = sdhci_readw(sdhci, SDHCI_CLOCK_CONTROL);
+ clk &= ~SDHCI_CLOCK_CARD_EN;
+ sdhci_writew(sdhci, clk, SDHCI_CLOCK_CONTROL);
+
+ /* Set/clear the 1.8V signalling */
sdhci_writew(sdhci, ctrl, SDHCI_HOST_CONTROL2);
/* Switch the I/O rail voltage */
@@ -1075,10 +1092,23 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
rc = clk_enable(clk);
if (rc != 0)
goto err_clk_put;
+
+ if (!strcmp(dev_name(mmc_dev(host->mmc)), "sdhci-tegra.3")) {
+ tegra_host->emc_clk = clk_get(mmc_dev(host->mmc), "emc");
+ if (IS_ERR(tegra_host->emc_clk)) {
+ dev_err(mmc_dev(host->mmc), "clk err\n");
+ rc = PTR_ERR(tegra_host->emc_clk);
+ goto err_clk_put;
+ }
+ tegra_host->emc_max_clk =
+ clk_round_rate(tegra_host->emc_clk, ULONG_MAX);
+ }
+
pltfm_host->clk = clk;
pltfm_host->priv = tegra_host;
tegra_host->clk_enabled = true;
tegra_host->max_clk_limit = plat->max_clk_limit;
+ tegra_host->ddr_clk_limit = plat->ddr_clk_limit;
tegra_host->instance = pdev->id;
tegra_host->dpd = tegra_io_dpd_get(mmc_dev(host->mmc));
@@ -1098,6 +1128,11 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
host->mmc->caps |= MMC_CAP_NONREMOVABLE;
}
host->mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
+
+#ifdef CONFIG_MMC_BKOPS
+ host->mmc->caps |= MMC_CAP_BKOPS;
+#endif
+
#ifdef CONFIG_MMC_EMBEDDED_SDIO
/* Do not turn OFF embedded sdio cards as it support Wake on Wireless */
if (plat->mmc_data.embedded_sdio)
@@ -1120,6 +1155,7 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
return 0;
err_add_host:
+ clk_put(tegra_host->emc_clk);
clk_disable(pltfm_host->clk);
err_clk_put:
clk_put(pltfm_host->clk);
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 495586924d60..22814660bc34 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2330,20 +2330,34 @@ out:
int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state)
{
int ret = 0;
+ bool has_tuning_timer;
struct mmc_host *mmc = host->mmc;
sdhci_disable_card_detection(host);
/* Disable tuning since we are suspending */
- if (host->version >= SDHCI_SPEC_300 && host->tuning_count &&
- host->tuning_mode == SDHCI_TUNING_MODE_1) {
+ has_tuning_timer = host->version >= SDHCI_SPEC_300 &&
+ host->tuning_count && host->tuning_mode == SDHCI_TUNING_MODE_1;
+ if (has_tuning_timer) {
host->flags &= ~SDHCI_NEEDS_RETUNING;
mod_timer(&host->tuning_timer, jiffies +
host->tuning_count * HZ);
}
- if (mmc->card)
+ if (mmc->card) {
ret = mmc_suspend_host(host->mmc);
+ if (ret) {
+ if (has_tuning_timer) {
+ host->flags |= SDHCI_NEEDS_RETUNING;
+ mod_timer(&host->tuning_timer, jiffies +
+ host->tuning_count * HZ);
+ }
+
+ sdhci_enable_card_detection(host);
+
+ return ret;
+ }
+ }
if (mmc->pm_flags & MMC_PM_KEEP_POWER)
host->card_int_set = sdhci_readl(host, SDHCI_INT_ENABLE) &
diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
index 34f83a4c9561..dc44c5c33e01 100644
--- a/drivers/mmc/host/sh_mmcif.c
+++ b/drivers/mmc/host/sh_mmcif.c
@@ -277,13 +277,8 @@ static void sh_mmcif_start_dma_tx(struct sh_mmcif_host *host)
DMA_TO_DEVICE);
if (ret > 0) {
host->dma_active = true;
-<<<<<<< HEAD
- desc = chan->device->device_prep_slave_sg(chan, sg, ret,
- DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-=======
desc = dmaengine_prep_slave_sg(chan, sg, ret,
DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
->>>>>>> 1605282... dmaengine/dma_slave: introduce inline wrappers
}
if (desc) {
diff --git a/drivers/mmc/host/tmio_mmc_dma.c b/drivers/mmc/host/tmio_mmc_dma.c
index d298e7bd26d2..def9c54f73f5 100644
--- a/drivers/mmc/host/tmio_mmc_dma.c
+++ b/drivers/mmc/host/tmio_mmc_dma.c
@@ -157,13 +157,8 @@ static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host)
ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_TO_DEVICE);
if (ret > 0)
-<<<<<<< HEAD
- desc = chan->device->device_prep_slave_sg(chan, sg, ret,
- DMA_TO_DEVICE, DMA_CTRL_ACK);
-=======
desc = dmaengine_prep_slave_sg(chan, sg, ret,
DMA_MEM_TO_DEV, DMA_CTRL_ACK);
->>>>>>> 1605282... dmaengine/dma_slave: introduce inline wrappers
if (desc) {
cookie = dmaengine_submit(desc);
diff --git a/drivers/mtd/maps/tegra_nor.c b/drivers/mtd/maps/tegra_nor.c
index b455fd5e1c00..505a2591f884 100644
--- a/drivers/mtd/maps/tegra_nor.c
+++ b/drivers/mtd/maps/tegra_nor.c
@@ -217,6 +217,8 @@ static void tegra_flash_dma(struct map_info *map,
bytes_remaining += (word32_count << 2);
break;
}
+ dma_sync_single_for_cpu(c->dev, c->dma_phys_buffer,
+ (current_transfer << 2), DMA_FROM_DEVICE);
memcpy((char *)(copy_to), (char *)(c->dma_virt_buffer),
(current_transfer << 2));
@@ -279,7 +281,7 @@ static int tegra_snor_controller_init(struct tegra_nor_info *info)
info->timing0_default = chip_parm->timing_default.timing0;
info->timing0_read = chip_parm->timing_read.timing0;
info->timing1_default = chip_parm->timing_default.timing1;
- info->timing1_read = chip_parm->timing_read.timing0;
+ info->timing1_read = chip_parm->timing_read.timing1;
snor_tegra_writel(info, info->timing1_default, TEGRA_SNOR_TIMING1_REG);
snor_tegra_writel(info, info->timing0_default, TEGRA_SNOR_TIMING0_REG);
diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c
index aa826d90f00d..c31b1185f492 100644
--- a/drivers/net/usb/cdc_ether.c
+++ b/drivers/net/usb/cdc_ether.c
@@ -469,6 +469,15 @@ static const struct driver_info wwan_info = {
.manage_power = cdc_manage_power,
};
+static const struct driver_info rmnet_info = {
+ .description = "Mobile Broadband Network Device",
+ .flags = FLAG_RMNET,
+ .bind = usbnet_cdc_bind,
+ .unbind = usbnet_cdc_unbind,
+ .status = usbnet_cdc_status,
+ .manage_power = cdc_manage_power,
+};
+
/*-------------------------------------------------------------------------*/
#define HUAWEI_VENDOR_ID 0x12D1
@@ -575,17 +584,17 @@ static const struct usb_device_id products [] = {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
USB_DEVICE(0x1983, 0x0310),
- .driver_info = (unsigned long)&wwan_info,
+ .driver_info = (unsigned long)&rmnet_info,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
USB_DEVICE(0x1983, 0x0321),
- .driver_info = (unsigned long)&wwan_info,
+ .driver_info = (unsigned long)&rmnet_info,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
USB_DEVICE(0x1983, 0x0327), /* 5AE */
- .driver_info = (unsigned long)&wwan_info,
+ .driver_info = (unsigned long)&rmnet_info,
},
/* Tango module */
@@ -593,7 +602,7 @@ static const struct usb_device_id products [] = {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
USB_DEVICE(0x0489,0xE03A),
- .driver_info = (unsigned long)&wwan_info,
+ .driver_info = (unsigned long)&rmnet_info,
},
/*
* WHITELIST!!!
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index 7b4687974987..370846911800 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -1,7 +1,7 @@
/***************************************************************************
*
* Copyright (C) 2007-2008 SMSC
- *
+ * Copyright (C) 2012 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
@@ -63,6 +63,11 @@ static int turbo_mode = true;
module_param(turbo_mode, bool, 0644);
MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction");
+static u8 mac_addr[6] = {0};
+static bool smsc_mac_addr_set;
+module_param_array_named(mac_addr, mac_addr, byte, NULL, 0);
+MODULE_PARM_DESC(mac_addr, "SMSC command line MAC address");
+
static int smsc95xx_read_reg(struct usbnet *dev, u32 index, u32 *data)
{
u32 *buf = kmalloc(4, GFP_KERNEL);
@@ -612,6 +617,15 @@ static void smsc95xx_init_mac_address(struct usbnet *dev)
}
}
+ /* try reading mac address from command line */
+ if (is_valid_ether_addr(mac_addr) && !smsc_mac_addr_set) {
+ memcpy(dev->net->dev_addr, mac_addr, sizeof(mac_addr));
+ smsc_mac_addr_set = true;
+ netif_dbg(dev, ifup, dev->net,
+ "MAC address read from command line");
+ return;
+ }
+
/* no eeprom, or eeprom values are invalid. generate random MAC */
random_ether_addr(dev->net->dev_addr);
netif_dbg(dev, ifup, dev->net, "MAC address set to random_ether_addr\n");
diff --git a/drivers/net/wireless/bcmdhd/Kconfig b/drivers/net/wireless/bcmdhd/Kconfig
index 427cd9911569..ef9ce5a00538 100644
--- a/drivers/net/wireless/bcmdhd/Kconfig
+++ b/drivers/net/wireless/bcmdhd/Kconfig
@@ -24,11 +24,6 @@ config BCMDHD_NVRAM_DIR
---help---
Path to the calibration file.
-choice
- prompt "Select API"
- depends on BCMDHD
- default BCMDHD_NOAPI
-
config BCMDHD_WEXT
bool "Enable WEXT support"
select WIRELESS_EXT
@@ -36,6 +31,27 @@ config BCMDHD_WEXT
help
Enables WEXT support
+config DHD_USE_STATIC_BUF
+ bool "Enable memory preallocation"
+ depends on BCMDHD
+ default n
+ ---help---
+ Use memory preallocated in platform
+
+config DHD_USE_SCHED_SCAN
+ bool "Use CFG80211 sched scan"
+ depends on BCMDHD && CFG80211
+ default n
+ ---help---
+ Use CFG80211 sched scan
+
+config DHD_ENABLE_P2P
+ bool "Enable Wifi Direct"
+ depends on BCMDHD && CFG80211
+ default n
+ ---help---
+ Use Enable Wifi Direct
+
config BCMDHD_CFG80211
bool "Enable CFG80211 support"
depends on CFG80211
@@ -47,8 +63,6 @@ config BCMDHD_NOAPI
help
No wireless API is needed
-endchoice
-
config BCMDHD_WIFI_CONTROL_FUNC
bool "Use bcmdhd_wlan device"
depends on BCMDHD
diff --git a/drivers/net/wireless/bcmdhd/Makefile b/drivers/net/wireless/bcmdhd/Makefile
index 85e93f7a56c3..2851388cf194 100644
--- a/drivers/net/wireless/bcmdhd/Makefile
+++ b/drivers/net/wireless/bcmdhd/Makefile
@@ -8,6 +8,7 @@ DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DBCMDRIVER \
-DNEW_COMPAT_WIRELESS -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT \
-DKEEP_ALIVE -DPKT_FILTER_SUPPORT \
-DEMBEDDED_PLATFORM \
+ -DSET_RANDOM_MAC_SOFTAP -DWL_CFG80211_STA_EVENT \
-Idrivers/net/wireless/bcmdhd -Idrivers/net/wireless/bcmdhd/include
ifeq ($(CONFIG_BCMDHD_WIFI_CONTROL_FUNC),y)
@@ -37,21 +38,26 @@ endif
DHDOFILES = aiutils.o bcmsdh_sdmmc_linux.o dhd_linux.o siutils.o bcmutils.o \
dhd_linux_sched.o bcmwifi.o dhd_sdio.o bcmevent.o dhd_bta.o hndpmu.o \
bcmsdh.o dhd_cdc.o bcmsdh_linux.o dhd_common.o linux_osl.o \
- bcmsdh_sdmmc.o dhd_custom_gpio.o sbutils.o wldev_common.o wl_android.o
+ bcmsdh_sdmmc.o dhd_custom_gpio.o sbutils.o wldev_common.o wl_android.o dhd_cfg80211.o
obj-$(CONFIG_BCMDHD) += bcmdhd.o
bcmdhd-objs += $(DHDOFILES)
ifeq ($(CONFIG_BCMDHD_WEXT),y)
bcmdhd-objs += wl_iw.o
-DHDCFLAGS += -DSOFTAP
+DHDCFLAGS += -DSOFTAP -DWL_WIRELESS_EXT
endif
-ifeq ($(CONFIG_BCMDHD_CFG80211),y)
-bcmdhd-objs += wl_cfg80211.o wl_cfgp2p.o dhd_linux_mon.o
+ifneq ($(CONFIG_CFG80211),)
+bcmdhd-objs += wl_cfg80211.o wl_cfgp2p.o wl_linux_mon.o
DHDCFLAGS += -DWL_CFG80211
endif
-
+ifneq ($(CONFIG_DHD_USE_SCHED_SCAN),)
+DHDCFLAGS += -DWL_SCHED_SCAN
+endif
+ifneq ($(CONFIG_DHD_ENABLE_P2P),)
+DHDCFLAGS += -DWL_ENABLE_P2P_IF
+endif
EXTRA_CFLAGS = $(DHDCFLAGS)
ifeq ($(CONFIG_BCMDHD),m)
EXTRA_LDFLAGS += --strip-debug
diff --git a/drivers/net/wireless/bcmdhd/aiutils.c b/drivers/net/wireless/bcmdhd/aiutils.c
index 059df8907928..5ca0993c9333 100644
--- a/drivers/net/wireless/bcmdhd/aiutils.c
+++ b/drivers/net/wireless/bcmdhd/aiutils.c
@@ -22,7 +22,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: aiutils.c,v 1.26.2.1 2010-03-09 18:41:21 Exp $
+ * $Id: aiutils.c,v 1.26.2.1 2010-03-09 18:41:21 $
*/
diff --git a/drivers/net/wireless/bcmdhd/bcmevent.c b/drivers/net/wireless/bcmdhd/bcmevent.c
index 24581ddd353c..6a25d9a5a57f 100644
--- a/drivers/net/wireless/bcmdhd/bcmevent.c
+++ b/drivers/net/wireless/bcmdhd/bcmevent.c
@@ -20,7 +20,7 @@
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
- * $Id: bcmevent.c,v 1.8.2.7 2011-02-01 06:23:39 Exp $
+ * $Id: bcmevent.c,v 1.8.2.7 2011-02-01 06:23:39 $
*/
#include <typedefs.h>
@@ -29,7 +29,7 @@
#include <proto/bcmeth.h>
#include <proto/bcmevent.h>
-#if WLC_E_LAST != 85
+#if WLC_E_LAST != 87
#error "You need to add an entry to bcmevent_names[] for the new event"
#endif
@@ -117,8 +117,10 @@ const bcmevent_name_t bcmevent_names[] = {
{ WLC_E_PFN_SCAN_NONE, "PFN_SCAN_NONE" },
{ WLC_E_PFN_SCAN_ALLGONE, "PFN_SCAN_ALLGONE" },
#ifdef SOFTAP
- { WLC_E_GTK_PLUMBED, "GTK_PLUMBED" }
+ { WLC_E_GTK_PLUMBED, "GTK_PLUMBED" },
#endif
+ { WLC_E_ASSOC_REQ_IE, "ASSOC_REQ_IE" },
+ { WLC_E_ASSOC_RESP_IE, "ASSOC_RESP_IE" }
};
diff --git a/drivers/net/wireless/bcmdhd/bcmsdh.c b/drivers/net/wireless/bcmdhd/bcmsdh.c
index 918c8e648f13..f67b13a03a1c 100644
--- a/drivers/net/wireless/bcmdhd/bcmsdh.c
+++ b/drivers/net/wireless/bcmdhd/bcmsdh.c
@@ -22,7 +22,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: bcmsdh.c 275784 2011-08-04 22:41:49Z $
+ * $Id: bcmsdh.c 300445 2011-12-03 05:37:20Z $
*/
/**
diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_linux.c b/drivers/net/wireless/bcmdhd/bcmsdh_linux.c
index d467e4b5630e..237af4ae8417 100644
--- a/drivers/net/wireless/bcmdhd/bcmsdh_linux.c
+++ b/drivers/net/wireless/bcmdhd/bcmsdh_linux.c
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: bcmsdh_linux.c,v 1.72.6.5 2010-12-23 01:13:15 Exp $
+ * $Id: bcmsdh_linux.c 312788 2012-02-03 23:06:32Z $
*/
/**
@@ -148,17 +148,6 @@ static int __devexit bcmsdh_remove_bcmdhd(struct device *dev);
#endif /* BCMLXSDMMC */
#ifndef BCMLXSDMMC
-static struct device_driver bcmsdh_driver = {
- .name = "pxa2xx-mci",
- .bus = &platform_bus_type,
- .probe = bcmsdh_probe_bcmdhd,
- .remove = bcmsdh_remove_bcmdhd,
- .suspend = NULL,
- .resume = NULL,
- };
-#endif /* BCMLXSDMMC */
-
-#ifndef BCMLXSDMMC
static
#endif /* BCMLXSDMMC */
int bcmsdh_probe_bcmdhd(struct device *dev)
@@ -277,6 +266,7 @@ int bcmsdh_remove_bcmdhd(struct device *dev)
sdhc = sdhcinfo;
drvinfo.detach(sdhc->ch);
bcmsdh_detach(sdhc->osh, sdhc->sdh);
+
/* find the SDIO Host Controller state for this pdev and take it out from the list */
for (sdhc = sdhcinfo, prev = NULL; sdhc; sdhc = sdhc->next) {
if (sdhc->dev == (void *)dev) {
@@ -293,7 +283,6 @@ int bcmsdh_remove_bcmdhd(struct device *dev)
return 0;
}
-
/* release SDIO Host Controller info */
osh = sdhc->osh;
MFREE(osh, sdhc, sizeof(bcmsdh_hc_t));
@@ -534,13 +523,8 @@ bcmsdh_register(bcmsdh_driver_t *driver)
drvinfo = *driver;
#if defined(BCMPLATFORM_BUS)
-#if defined(BCMLXSDMMC)
SDLX_MSG(("Linux Kernel SDIO/MMC Driver\n"));
error = sdio_function_init();
-#else
- SDLX_MSG(("Intel PXA270 SDIO Driver\n"));
- error = driver_register(&bcmsdh_driver);
-#endif /* defined(BCMLXSDMMC) */
return error;
#endif /* defined(BCMPLATFORM_BUS) */
@@ -568,14 +552,12 @@ bcmsdh_unregister(void)
if (bcmsdh_pci_driver.node.next)
#endif
-#if defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC)
- driver_unregister(&bcmsdh_driver);
-#endif
#if defined(BCMLXSDMMC)
sdio_function_cleanup();
#endif /* BCMLXSDMMC */
+
#if !defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC)
- pci_unregister_driver(&bcmsdh_pci_driver);
+ pci_unregister_driver(&bcmsdh_pci_driver);
#endif /* BCMPLATFORM_BUS */
}
@@ -614,13 +596,6 @@ static irqreturn_t wlan_oob_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
-void *bcmsdh_get_drvdata(void)
-{
- if (!sdhcinfo)
- return NULL;
- return dev_get_drvdata(sdhcinfo->dev);
-}
-
int bcmsdh_register_oob_intr(void * dhdp)
{
int error = 0;
@@ -674,6 +649,16 @@ void bcmsdh_unregister_oob_intr(void)
}
}
#endif /* defined(OOB_INTR_ONLY) */
+
+#if defined(BCMLXSDMMC)
+void *bcmsdh_get_drvdata(void)
+{
+ if (!sdhcinfo)
+ return NULL;
+ return dev_get_drvdata(sdhcinfo->dev);
+}
+#endif
+
/* Module parameters specific to each host-controller driver */
extern uint sd_msglevel; /* Debug message level */
@@ -697,6 +682,10 @@ module_param(sd_hiok, uint, 0);
extern uint sd_f2_blocksize;
module_param(sd_f2_blocksize, int, 0);
+#ifdef BCMSDIOH_STD
+extern int sd_uhsimode;
+module_param(sd_uhsimode, int, 0);
+#endif
#ifdef BCMSDH_MODULE
EXPORT_SYMBOL(bcmsdh_attach);
diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c
index 7499a1ec55fd..e67eeca1f99c 100644
--- a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c
+++ b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: bcmsdh_sdmmc.c 282820 2011-09-09 15:40:35Z $
+ * $Id: bcmsdh_sdmmc.c 314904 2012-02-14 21:36:04Z $
*/
#include <typedefs.h>
@@ -35,6 +35,7 @@
#include <sdiovar.h> /* ioctl/iovars */
#include <linux/mmc/core.h>
+#include <linux/mmc/card.h>
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_ids.h>
@@ -148,6 +149,7 @@ sdioh_attach(osl_t *osh, void *bar0, uint irq)
sd->sd_blockmode = TRUE;
sd->use_client_ints = TRUE;
sd->client_block_size[0] = 64;
+ sd->use_rxchain = FALSE;
gInstance->sd = sd;
@@ -459,6 +461,7 @@ sdioh_iovar_op(sdioh_info_t *si, const char *name,
bcopy(params, &int_val, sizeof(int_val));
bool_val = (int_val != 0) ? TRUE : FALSE;
+ BCM_REFERENCE(bool_val);
actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
switch (actionid) {
@@ -522,7 +525,7 @@ sdioh_iovar_op(sdioh_info_t *si, const char *name,
}
case IOV_GVAL(IOV_RXCHAIN):
- int_val = FALSE;
+ int_val = (int32)si->use_rxchain;
bcopy(&int_val, arg, val_size);
break;
@@ -689,14 +692,9 @@ sdioh_enable_hw_oob_intr(sdioh_info_t *sd, bool enable)
uint8 data;
if (enable)
- data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE; /* enable hw oob interrupt */
+ data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE | SDIO_SEPINT_ACT_HI;
else
- data = SDIO_SEPINT_ACT_HI; /* disable hw oob interrupt */
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
- /* Needed for Android Linux Kernel 2.6.35 */
- data |= SDIO_SEPINT_ACT_HI; /* Active HIGH */
-#endif
+ data = SDIO_SEPINT_ACT_HI;
status = sdioh_request_byte(sd, SDIOH_WRITE, 0, SDIOD_CCCR_BRCM_SEPINT, &data);
return status;
@@ -912,8 +910,12 @@ sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func,
bool fifo = (fix_inc == SDIOH_DATA_FIX);
uint32 SGCount = 0;
int err_ret = 0;
-
- void *pnext;
+ void *pnext, *pprev;
+ uint ttl_len, dma_len, lft_len, xfred_len, pkt_len;
+ uint blk_num;
+ struct mmc_request mmc_req;
+ struct mmc_command mmc_cmd;
+ struct mmc_data mmc_dat;
sd_trace(("%s: Enter\n", __FUNCTION__));
@@ -921,66 +923,148 @@ sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func,
DHD_PM_RESUME_WAIT(sdioh_request_packet_wait);
DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
- /* Claim host controller */
- sdio_claim_host(gInstance->func[func]);
- for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) {
- uint pkt_len = PKTLEN(sd->osh, pnext);
- pkt_len += 3;
- pkt_len &= 0xFFFFFFFC;
+ ttl_len = xfred_len = 0;
+ /* at least 4 bytes alignment of skb buff is guaranteed */
+ for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext))
+ ttl_len += PKTLEN(sd->osh, pnext);
-#ifdef CONFIG_MMC_MSM7X00A
- if ((pkt_len % 64) == 32) {
- sd_trace(("%s: Rounding up TX packet +=32\n", __FUNCTION__));
- pkt_len += 32;
- }
-#endif /* CONFIG_MMC_MSM7X00A */
- /* Make sure the packet is aligned properly. If it isn't, then this
- * is the fault of sdioh_request_buffer() which is supposed to give
- * us something we can work with.
- */
- ASSERT(((uint32)(PKTDATA(sd->osh, pkt)) & DMA_ALIGN_MASK) == 0);
-
- if ((write) && (!fifo)) {
- err_ret = sdio_memcpy_toio(gInstance->func[func], addr,
- ((uint8*)PKTDATA(sd->osh, pnext)),
- pkt_len);
- } else if (write) {
- err_ret = sdio_memcpy_toio(gInstance->func[func], addr,
- ((uint8*)PKTDATA(sd->osh, pnext)),
- pkt_len);
- } else if (fifo) {
- err_ret = sdio_readsb(gInstance->func[func],
- ((uint8*)PKTDATA(sd->osh, pnext)),
- addr,
- pkt_len);
- } else {
- err_ret = sdio_memcpy_fromio(gInstance->func[func],
- ((uint8*)PKTDATA(sd->osh, pnext)),
- addr,
+ if (!sd->use_rxchain || ttl_len <= sd->client_block_size[func]) {
+ blk_num = 0;
+ dma_len = 0;
+ } else {
+ blk_num = ttl_len / sd->client_block_size[func];
+ dma_len = blk_num * sd->client_block_size[func];
+ }
+ lft_len = ttl_len - dma_len;
+
+ sd_trace(("%s: %s %dB to func%d:%08x, %d blks with DMA, %dB leftover\n",
+ __FUNCTION__, write ? "W" : "R",
+ ttl_len, func, addr, blk_num, lft_len));
+
+ if (0 != dma_len) {
+ memset(&mmc_req, 0, sizeof(struct mmc_request));
+ memset(&mmc_cmd, 0, sizeof(struct mmc_command));
+ memset(&mmc_dat, 0, sizeof(struct mmc_data));
+
+ /* Set up DMA descriptors */
+ pprev = pkt;
+ for (pnext = pkt;
+ pnext && dma_len;
+ pnext = PKTNEXT(sd->osh, pnext)) {
+ pkt_len = PKTLEN(sd->osh, pnext);
+
+ if (dma_len > pkt_len)
+ dma_len -= pkt_len;
+ else {
+ pkt_len = xfred_len = dma_len;
+ dma_len = 0;
+ pkt = pnext;
+ }
+
+ sg_set_buf(&sd->sg_list[SGCount++],
+ (uint8*)PKTDATA(sd->osh, pnext),
pkt_len);
- }
- if (err_ret) {
- sd_err(("%s: %s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=0x%08x\n",
- __FUNCTION__,
- (write) ? "TX" : "RX",
- pnext, SGCount, addr, pkt_len, err_ret));
- } else {
- sd_trace(("%s: %s xfr'd %p[%d], addr=0x%05x, len=%d\n",
- __FUNCTION__,
- (write) ? "TX" : "RX",
- pnext, SGCount, addr, pkt_len));
+ if (SGCount >= SDIOH_SDMMC_MAX_SG_ENTRIES) {
+ sd_err(("%s: sg list entries exceed limit\n",
+ __FUNCTION__));
+ return (SDIOH_API_RC_FAIL);
+ }
}
- if (!fifo) {
- addr += pkt_len;
- }
- SGCount ++;
+ mmc_dat.sg = sd->sg_list;
+ mmc_dat.sg_len = SGCount;
+ mmc_dat.blksz = sd->client_block_size[func];
+ mmc_dat.blocks = blk_num;
+ mmc_dat.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
+
+ mmc_cmd.opcode = 53; /* SD_IO_RW_EXTENDED */
+ mmc_cmd.arg = write ? 1<<31 : 0;
+ mmc_cmd.arg |= (func & 0x7) << 28;
+ mmc_cmd.arg |= 1<<27;
+ mmc_cmd.arg |= fifo ? 0 : 1<<26;
+ mmc_cmd.arg |= (addr & 0x1FFFF) << 9;
+ mmc_cmd.arg |= blk_num & 0x1FF;
+ mmc_cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC;
+
+ mmc_req.cmd = &mmc_cmd;
+ mmc_req.data = &mmc_dat;
+
+ sdio_claim_host(gInstance->func[func]);
+ mmc_set_data_timeout(&mmc_dat, gInstance->func[func]->card);
+ mmc_wait_for_req(gInstance->func[func]->card->host, &mmc_req);
+ sdio_release_host(gInstance->func[func]);
+ err_ret = mmc_cmd.error? mmc_cmd.error : mmc_dat.error;
+ if (0 != err_ret) {
+ sd_err(("%s:CMD53 %s failed with code %d\n",
+ __FUNCTION__,
+ write ? "write" : "read",
+ err_ret));
+ sd_err(("%s:Disabling rxchain and fire it with PIO\n",
+ __FUNCTION__));
+ sd->use_rxchain = FALSE;
+ pkt = pprev;
+ lft_len = ttl_len;
+ } else if (!fifo) {
+ addr = addr + ttl_len - lft_len - dma_len;
+ }
}
- /* Release host controller */
- sdio_release_host(gInstance->func[func]);
+ /* PIO mode */
+ if (0 != lft_len) {
+ /* Claim host controller */
+ sdio_claim_host(gInstance->func[func]);
+ for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) {
+ uint8 *buf = (uint8*)PKTDATA(sd->osh, pnext) +
+ xfred_len;
+ pkt_len = PKTLEN(sd->osh, pnext);
+ if (0 != xfred_len) {
+ pkt_len -= xfred_len;
+ xfred_len = 0;
+ }
+ pkt_len = (pkt_len + 3) & 0xFFFFFFFC;
+#ifdef CONFIG_MMC_MSM7X00A
+ if ((pkt_len % 64) == 32) {
+ sd_trace(("%s: Rounding up TX packet +=32\n", __FUNCTION__));
+ pkt_len += 32;
+ }
+#endif /* CONFIG_MMC_MSM7X00A */
+
+ if ((write) && (!fifo))
+ err_ret = sdio_memcpy_toio(
+ gInstance->func[func],
+ addr, buf, pkt_len);
+ else if (write)
+ err_ret = sdio_memcpy_toio(
+ gInstance->func[func],
+ addr, buf, pkt_len);
+ else if (fifo)
+ err_ret = sdio_readsb(
+ gInstance->func[func],
+ buf, addr, pkt_len);
+ else
+ err_ret = sdio_memcpy_fromio(
+ gInstance->func[func],
+ buf, addr, pkt_len);
+
+ if (err_ret)
+ sd_err(("%s: %s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=%d\n",
+ __FUNCTION__,
+ (write) ? "TX" : "RX",
+ pnext, SGCount, addr, pkt_len, err_ret));
+ else
+ sd_trace(("%s: %s xfr'd %p[%d], addr=0x%05x, len=%d\n",
+ __FUNCTION__,
+ (write) ? "TX" : "RX",
+ pnext, SGCount, addr, pkt_len));
+
+ if (!fifo)
+ addr += pkt_len;
+ SGCount ++;
+ }
+ sdio_release_host(gInstance->func[func]);
+ }
sd_trace(("%s: Exit\n", __FUNCTION__));
return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
@@ -1013,11 +1097,11 @@ sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, u
if (pkt == NULL) {
sd_data(("%s: Creating new %s Packet, len=%d\n",
__FUNCTION__, write ? "TX" : "RX", buflen_u));
-#ifdef DHD_USE_STATIC_BUF
+#ifdef CONFIG_DHD_USE_STATIC_BUF
if (!(mypkt = PKTGET_STATIC(sd->osh, buflen_u, write ? TRUE : FALSE))) {
#else
if (!(mypkt = PKTGET(sd->osh, buflen_u, write ? TRUE : FALSE))) {
-#endif /* DHD_USE_STATIC_BUF */
+#endif /* CONFIG_DHD_USE_STATIC_BUF */
sd_err(("%s: PKTGET failed: len %d\n",
__FUNCTION__, buflen_u));
return SDIOH_API_RC_FAIL;
@@ -1034,11 +1118,11 @@ sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, u
if (!write) {
bcopy(PKTDATA(sd->osh, mypkt), buffer, buflen_u);
}
-#ifdef DHD_USE_STATIC_BUF
+#ifdef CONFIG_DHD_USE_STATIC_BUF
PKTFREE_STATIC(sd->osh, mypkt, write ? TRUE : FALSE);
#else
PKTFREE(sd->osh, mypkt, write ? TRUE : FALSE);
-#endif /* DHD_USE_STATIC_BUF */
+#endif /* CONFIG_DHD_USE_STATIC_BUF */
} else if (((uint32)(PKTDATA(sd->osh, pkt)) & DMA_ALIGN_MASK) != 0) {
/* Case 2: We have a packet, but it is unaligned. */
@@ -1047,11 +1131,11 @@ sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, u
sd_data(("%s: Creating aligned %s Packet, len=%d\n",
__FUNCTION__, write ? "TX" : "RX", PKTLEN(sd->osh, pkt)));
-#ifdef DHD_USE_STATIC_BUF
+#ifdef CONFIG_DHD_USE_STATIC_BUF
if (!(mypkt = PKTGET_STATIC(sd->osh, PKTLEN(sd->osh, pkt), write ? TRUE : FALSE))) {
#else
if (!(mypkt = PKTGET(sd->osh, PKTLEN(sd->osh, pkt), write ? TRUE : FALSE))) {
-#endif /* DHD_USE_STATIC_BUF */
+#endif /* CONFIG_DHD_USE_STATIC_BUF */
sd_err(("%s: PKTGET failed: len %d\n",
__FUNCTION__, PKTLEN(sd->osh, pkt)));
return SDIOH_API_RC_FAIL;
@@ -1072,11 +1156,11 @@ sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, u
PKTDATA(sd->osh, pkt),
PKTLEN(sd->osh, mypkt));
}
-#ifdef DHD_USE_STATIC_BUF
+#ifdef CONFIG_DHD_USE_STATIC_BUF
PKTFREE_STATIC(sd->osh, mypkt, write ? TRUE : FALSE);
#else
PKTFREE(sd->osh, mypkt, write ? TRUE : FALSE);
-#endif /* DHD_USE_STATIC_BUF */
+#endif /* CONFIG_DHD_USE_STATIC_BUF */
} else { /* case 3: We have a packet and it is aligned. */
sd_data(("%s: Aligned %s Packet, direct DMA\n",
__FUNCTION__, write ? "Tx" : "Rx"));
@@ -1190,6 +1274,7 @@ static void IRQHandlerF2(struct sdio_func *func)
sd = gInstance->sd;
ASSERT(sd != NULL);
+ BCM_REFERENCE(sd);
}
#endif /* !defined(OOB_INTR_ONLY) */
@@ -1241,8 +1326,10 @@ sdioh_start(sdioh_info_t *si, int stage)
2.6.27. The implementation prior to that is buggy, and needs broadcom's
patch for it
*/
- if ((ret = sdio_reset_comm(gInstance->func[0]->card)))
+ if ((ret = sdio_reset_comm(gInstance->func[0]->card))) {
sd_err(("%s Failed, error = %d\n", __FUNCTION__, ret));
+ return ret;
+ }
else {
sd->num_funcs = 2;
sd->sd_blockmode = TRUE;
diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c
index 1a370862b334..656953939b71 100644
--- a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c
+++ b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: bcmsdh_sdmmc_linux.c,v 1.8.6.2 2011-02-01 18:38:36 Exp $
+ * $Id: bcmsdh_sdmmc_linux.c 312783 2012-02-03 22:53:56Z $
*/
#include <typedefs.h>
@@ -55,13 +55,22 @@
#if !defined(SDIO_DEVICE_ID_BROADCOM_4330)
#define SDIO_DEVICE_ID_BROADCOM_4330 0x4330
#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4330) */
+#if !defined(SDIO_DEVICE_ID_BROADCOM_4334)
+#define SDIO_DEVICE_ID_BROADCOM_4334 0x4334
+#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4334) */
+#if !defined(SDIO_DEVICE_ID_BROADCOM_4324)
+#define SDIO_DEVICE_ID_BROADCOM_4324 0x4324
+#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4324) */
+#if !defined(SDIO_DEVICE_ID_BROADCOM_43239)
+#define SDIO_DEVICE_ID_BROADCOM_43239 43239
+#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_43239) */
#include <bcmsdh_sdmmc.h>
#include <dhd_dbg.h>
#ifdef WL_CFG80211
-extern void wl_cfg80211_set_sdio_func(void *func);
+extern void wl_cfg80211_set_parent_dev(void *dev);
#endif
extern void sdioh_sdmmc_devintr_off(sdioh_info_t *sd);
@@ -118,7 +127,7 @@ static int bcmsdh_sdmmc_probe(struct sdio_func *func,
if (func->num == 2) {
#ifdef WL_CFG80211
- wl_cfg80211_set_sdio_func(func);
+ wl_cfg80211_set_parent_dev(&func->dev);
#endif
sd_trace(("F2 found, calling bcmsdh_probe_bcmdhd...\n"));
ret = bcmsdh_probe_bcmdhd(&func->dev);
@@ -153,12 +162,15 @@ static const struct sdio_device_id bcmsdh_sdmmc_ids[] = {
{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325) },
{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4319) },
{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4330) },
+ { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4334) },
+ { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4324) },
+ { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43239) },
{ /* end: all zeroes */ },
};
MODULE_DEVICE_TABLE(sdio, bcmsdh_sdmmc_ids);
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM)
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM)
static int bcmsdh_sdmmc_suspend(struct device *pdev)
{
struct sdio_func *func = dev_to_sdio_func(pdev);
@@ -167,12 +179,30 @@ static int bcmsdh_sdmmc_suspend(struct device *pdev)
if (func->num != 2)
return 0;
+
+ sd_trace(("%s Enter\n", __FUNCTION__));
+
if (dhd_os_check_wakelock(bcmsdh_get_drvdata()))
return -EBUSY;
+
+
+ sdio_flags = sdio_get_host_pm_caps(func);
+
+ if (!(sdio_flags & MMC_PM_KEEP_POWER)) {
+ sd_err(("%s: can't keep power while host is suspended\n", __FUNCTION__));
+ return -EINVAL;
+ }
+
+ /* keep power while host suspended */
+ ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
+ if (ret) {
+ sd_err(("%s: error while trying to keep power\n", __FUNCTION__));
+ return ret;
+ }
+
#if defined(OOB_INTR_ONLY)
bcmsdh_oob_intr_set(0);
-#endif
- smp_mb();
+#endif /* defined(OOB_INTR_ONLY) */
sdio_flags = sdio_get_host_pm_caps(func);
@@ -191,6 +221,7 @@ static int bcmsdh_sdmmc_suspend(struct device *pdev)
}
dhd_mmc_suspend = TRUE;
+ smp_mb();
out:
return ret;
@@ -198,15 +229,16 @@ out:
static int bcmsdh_sdmmc_resume(struct device *pdev)
{
+#if defined(OOB_INTR_ONLY)
struct sdio_func *func = dev_to_sdio_func(pdev);
-
- if (func->num != 2)
- return 0;
+#endif
+ sd_trace(("%s Enter\n", __FUNCTION__));
dhd_mmc_suspend = FALSE;
#if defined(OOB_INTR_ONLY)
- if (dhd_os_check_if_up(bcmsdh_get_drvdata()))
+ if ((func->num == 2) && dhd_os_check_if_up(bcmsdh_get_drvdata()))
bcmsdh_oob_intr_set(1);
-#endif
+#endif /* (OOB_INTR_ONLY) */
+
smp_mb();
return 0;
}
@@ -215,18 +247,18 @@ static const struct dev_pm_ops bcmsdh_sdmmc_pm_ops = {
.suspend = bcmsdh_sdmmc_suspend,
.resume = bcmsdh_sdmmc_resume,
};
-#endif
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) */
static struct sdio_driver bcmsdh_sdmmc_driver = {
.probe = bcmsdh_sdmmc_probe,
.remove = bcmsdh_sdmmc_remove,
.name = "bcmsdh_sdmmc",
.id_table = bcmsdh_sdmmc_ids,
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM)
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM)
.drv = {
.pm = &bcmsdh_sdmmc_pm_ops,
},
-#endif
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) */
};
struct sdos_info {
diff --git a/drivers/net/wireless/bcmdhd/bcmutils.c b/drivers/net/wireless/bcmdhd/bcmutils.c
index fbdd7cd2d19b..6b578e653648 100644
--- a/drivers/net/wireless/bcmdhd/bcmutils.c
+++ b/drivers/net/wireless/bcmdhd/bcmutils.c
@@ -20,7 +20,7 @@
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
- * $Id: bcmutils.c,v 1.277.2.18 2011-01-26 02:32:08 Exp $
+ * $Id: bcmutils.c,v 1.277.2.18 2011-01-26 02:32:08 $
*/
#include <typedefs.h>
@@ -987,7 +987,6 @@ pktsetprio(void *pkt, bool update_vtag)
return (rc | priority);
}
-#ifndef BCM_BOOTLOADER
static char bcm_undeferrstr[32];
static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
@@ -1009,7 +1008,6 @@ bcmerrorstr(int bcmerror)
return bcmerrorstrtable[-bcmerror];
}
-#endif /* !BCM_BOOTLOADER */
diff --git a/drivers/net/wireless/bcmdhd/dhd.h b/drivers/net/wireless/bcmdhd/dhd.h
index 1b7242d48280..5ff5c218ddcf 100644
--- a/drivers/net/wireless/bcmdhd/dhd.h
+++ b/drivers/net/wireless/bcmdhd/dhd.h
@@ -24,7 +24,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: dhd.h 290844 2011-10-20 08:54:39Z $
+ * $Id: dhd.h 328934 2012-04-23 05:15:42Z $
*/
/****************
@@ -76,13 +76,24 @@ enum dhd_bus_state {
/* Firmware requested operation mode */
#define STA_MASK 0x0001
-#define HOSTAPD_MASK 0x0002
+#define HOSTAPD_MASK 0x0002
#define WFD_MASK 0x0004
-#define SOFTAP_FW_MASK 0x0008
+#define SOFTAP_FW_MASK 0x0008
+#define P2P_GO_ENABLED 0x0010
+#define P2P_GC_ENABLED 0x0020
+#define CONCURENT_MASK 0x00F0
+
+#define MANUFACTRING_FW "WLTEST"
/* max sequential rxcntl timeouts to set HANG event */
#define MAX_CNTL_TIMEOUT 2
+#define DHD_SCAN_ACTIVE_TIME 40 /* ms : Embedded default Active setting from DHD Driver */
+#define DHD_SCAN_PASSIVE_TIME 130 /* ms: Embedded default Passive setting from DHD Driver */
+
+#define DHD_BEACON_TIMEOUT_NORMAL 4
+#define DHD_BEACON_TIMEOUT_HIGH 10
+
enum dhd_bus_wake_state {
WAKE_LOCK_OFF,
WAKE_LOCK_PRIV,
@@ -115,8 +126,7 @@ typedef enum {
DHD_IF_DELETING
} dhd_if_state_t;
-
-#if defined(DHD_USE_STATIC_BUF)
+#if defined(CONFIG_DHD_USE_STATIC_BUF)
uint8* dhd_os_prealloc(void *osh, int section, uint size);
void dhd_os_prefree(void *osh, void *addr, uint size);
@@ -128,7 +138,7 @@ void dhd_os_prefree(void *osh, void *addr, uint size);
#define DHD_OS_PREALLOC(osh, section, size) MALLOC(osh, size)
#define DHD_OS_PREFREE(osh, addr, size) MFREE(osh, addr, size)
-#endif /* defined(DHD_USE_STATIC_BUF) */
+#endif /* defined(CONFIG_DHD_USE_STATIC_BUF) */
/* Packet alignment for most efficient SDIO (can change based on platform) */
#ifndef DHD_SDALIGN
@@ -202,9 +212,11 @@ typedef struct dhd_pub {
char eventmask[WL_EVENTING_MASK_LEN];
int op_mode; /* STA, HostAPD, WFD, SoftAP */
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK)
- struct wake_lock wakelock[WAKE_LOCK_MAX];
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_HAS_WAKELOCK) */
+/* Set this to 1 to use a seperate interface (p2p0) for p2p operations.
+ * For ICS MR1 releases it should be disable to be compatable with ICS MR1 Framework
+ * see target dhd-cdc-sdmmc-panda-cfg80211-icsmr1-gpl-debug in Makefile
+ */
+
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
struct mutex wl_start_stop_lock; /* lock/unlock for Android start/stop */
struct mutex wl_softap_lock; /* lock/unlock for any SoftAP/STA settings */
@@ -286,7 +298,8 @@ void dhd_os_spin_unlock(dhd_pub_t *pub, unsigned long flags);
extern int dhd_os_wake_lock(dhd_pub_t *pub);
extern int dhd_os_wake_unlock(dhd_pub_t *pub);
extern int dhd_os_wake_lock_timeout(dhd_pub_t *pub);
-extern int dhd_os_wake_lock_timeout_enable(dhd_pub_t *pub, int val);
+extern int dhd_os_wake_lock_rx_timeout_enable(dhd_pub_t *pub, int val);
+extern int dhd_os_wake_lock_ctrl_timeout_enable(dhd_pub_t *pub, int val);
inline static void MUTEX_LOCK_SOFTAP_SET_INIT(dhd_pub_t * dhdp)
{
@@ -312,10 +325,10 @@ inline static void MUTEX_UNLOCK_SOFTAP_SET(dhd_pub_t * dhdp)
#define DHD_OS_WAKE_LOCK(pub) dhd_os_wake_lock(pub)
#define DHD_OS_WAKE_UNLOCK(pub) dhd_os_wake_unlock(pub)
#define DHD_OS_WAKE_LOCK_TIMEOUT(pub) dhd_os_wake_lock_timeout(pub)
-#define DHD_OS_WAKE_LOCK_TIMEOUT_ENABLE(pub, val) dhd_os_wake_lock_timeout_enable(pub, val)
-
-#define DHD_PACKET_TIMEOUT 1
-#define DHD_EVENT_TIMEOUT 2
+#define DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(pub, val) dhd_os_wake_lock_rx_timeout_enable(pub, val)
+#define DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(pub, val) dhd_os_wake_lock_ctrl_timeout_enable(pub, val)
+#define DHD_PACKET_TIMEOUT_MS 1000
+#define DHD_EVENT_TIMEOUT_MS 1500
/* interface operations (register, remove) should be atomic, use this lock to prevent race
* condition among wifi on/off and interface operation functions
@@ -369,6 +382,12 @@ extern int dhd_net_attach(dhd_pub_t *dhdp, int idx);
/* Indication from bus module regarding removal/absence of dongle */
extern void dhd_detach(dhd_pub_t *dhdp);
+#if defined(WLP2P) && defined(WL_CFG80211)
+/* To allow attach/detach calls corresponding to p2p0 interface */
+extern int dhd_attach_p2p(dhd_pub_t *);
+extern int dhd_detach_p2p(dhd_pub_t *);
+#endif /* WLP2P && WL_CFG80211 */
+
extern void dhd_free(dhd_pub_t *dhdp);
/* Indication from bus module to change flow-control state */
@@ -411,6 +430,9 @@ extern int dhd_custom_get_mac_address(unsigned char *buf);
extern void dhd_os_sdunlock_sndup_rxq(dhd_pub_t * pub);
extern void dhd_os_sdlock_eventq(dhd_pub_t * pub);
extern void dhd_os_sdunlock_eventq(dhd_pub_t * pub);
+extern bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret);
+
+#ifdef PNO_SUPPORT
extern int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled);
extern int dhd_pno_clean(dhd_pub_t *dhd);
extern int dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid,
@@ -421,17 +443,20 @@ extern int dhd_dev_pno_set(struct net_device *dev, wlc_ssid_t* ssids_local,
int nssid, ushort scan_fr, int pno_repeat, int pno_freq_expo_max);
extern int dhd_dev_pno_enable(struct net_device *dev, int pfn_enabled);
extern int dhd_dev_get_pno_status(struct net_device *dev);
-extern int dhd_get_dtim_skip(dhd_pub_t *dhd);
-extern bool dhd_check_ap_wfd_mode_set(dhd_pub_t *dhd);
-extern bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret);
+#endif /* PNO_SUPPORT */
#define DHD_UNICAST_FILTER_NUM 0
#define DHD_BROADCAST_FILTER_NUM 1
#define DHD_MULTICAST4_FILTER_NUM 2
#define DHD_MULTICAST6_FILTER_NUM 3
+#define DHD_MDNS_FILTER_NUM 4
+extern int dhd_os_set_packet_filter(dhd_pub_t *dhdp, int val);
extern int net_os_set_packet_filter(struct net_device *dev, int val);
extern int net_os_rxfilter_add_remove(struct net_device *dev, int val, int num);
+extern int dhd_get_dtim_skip(dhd_pub_t *dhd);
+extern bool dhd_check_ap_wfd_mode_set(dhd_pub_t *dhd);
+
#ifdef DHD_DEBUG
extern int write_to_file(dhd_pub_t *dhd, uint8 *buf, int size);
#endif /* DHD_DEBUG */
@@ -453,7 +478,7 @@ extern int dhd_timeout_expired(dhd_timeout_t *tmo);
extern int dhd_ifname2idx(struct dhd_info *dhd, char *name);
extern int dhd_net2idx(struct dhd_info *dhd, struct net_device *net);
-extern struct net_device * dhd_idx2net(struct dhd_pub *dhd_pub, int ifidx);
+extern struct net_device * dhd_idx2net(void *pub, int ifidx);
extern int wl_host_event(dhd_pub_t *dhd_pub, int *idx, void *pktdata,
wl_event_msg_t *, void **data_ptr);
extern void wl_event_to_host_order(wl_event_msg_t * evt);
@@ -465,6 +490,7 @@ extern int dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uin
extern struct dhd_cmn *dhd_common_init(uint16 devid, osl_t *osh);
extern void dhd_common_deinit(dhd_pub_t *dhd_pub, dhd_cmn_t *sa_cmn);
+extern int dhd_do_driver_init(struct net_device *net);
extern int dhd_add_if(struct dhd_info *dhd, int ifidx, void *handle,
char *name, uint8 *mac_addr, uint32 flags, uint8 bssidx);
extern void dhd_del_if(struct dhd_info *dhd, int ifidx);
@@ -488,7 +514,8 @@ extern uint dhd_bus_status(dhd_pub_t *dhdp);
extern int dhd_bus_start(dhd_pub_t *dhdp);
extern int dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size);
extern void dhd_print_buf(void *pbuf, int len, int bytes_per_line);
-extern bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf);
+extern bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf, int *retval);
+extern uint dhd_bus_chip_id(dhd_pub_t *dhdp);
#if defined(KEEP_ALIVE)
extern int dhd_keep_alive_onoff(dhd_pub_t *dhd);
@@ -701,12 +728,6 @@ typedef struct dhd_pkttag {
#define DHD_PKTTAG_DSTN(tag) ((dhd_pkttag_t*)(tag))->dstn_ether
typedef int (*f_commitpkt_t)(void* ctx, void* p);
-int dhd_wlfc_enable(dhd_pub_t *dhd);
-int dhd_wlfc_interface_event(struct dhd_info *, uint8 action, uint8 ifid, uint8 iftype, uint8* ea);
-int dhd_wlfc_FIFOcreditmap_event(struct dhd_info *dhd, uint8* event_data);
-int dhd_wlfc_event(struct dhd_info *dhd);
-int dhd_os_wlfc_block(dhd_pub_t *pub);
-int dhd_os_wlfc_unblock(dhd_pub_t *pub);
#ifdef PROP_TXSTATUS_DEBUG
#define DHD_WLFC_CTRINC_MAC_CLOSE(entry) do { (entry)->closed_ct++; } while (0)
diff --git a/drivers/net/wireless/bcmdhd/dhd_cdc.c b/drivers/net/wireless/bcmdhd/dhd_cdc.c
index 3a4de96c0028..f16d81c9e198 100644
--- a/drivers/net/wireless/bcmdhd/dhd_cdc.c
+++ b/drivers/net/wireless/bcmdhd/dhd_cdc.c
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: dhd_cdc.c,v 1.51.6.31 2011-02-09 14:31:43 Exp $
+ * $Id: dhd_cdc.c 324280 2012-03-28 19:01:17Z $
*
* BDC is like CDC, except it includes a header for data packets to convey
* packet priority over the bus, and flags (e.g. to indicate checksum status
@@ -78,6 +78,8 @@ typedef struct dhd_prot {
unsigned char buf[WLC_IOCTL_MAXLEN + ROUND_UP_MARGIN];
} dhd_prot_t;
+extern int dhd_dbus_txdata(dhd_pub_t *dhdp, void *pktbuf);
+
static int
dhdcdc_msg(dhd_pub_t *dhd)
{
@@ -2174,6 +2176,7 @@ dhd_wlfc_init(dhd_pub_t *dhd)
WLFC_FLAGS_CREDIT_STATUS_SIGNALS |
WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE : 0;
+ dhd->wlfc_state = NULL;
/*
try to enable/disable signaling by sending "tlv" iovar. if that fails,
@@ -2460,10 +2463,10 @@ dhd_prot_attach(dhd_pub_t *dhd)
return 0;
fail:
-#ifndef DHD_USE_STATIC_BUF
+#ifndef CONFIG_DHD_USE_STATIC_BUF
if (cdc != NULL)
MFREE(dhd->osh, cdc, sizeof(dhd_prot_t));
-#endif
+#endif /* CONFIG_DHD_USE_STATIC_BUF */
return BCME_NOMEM;
}
@@ -2474,9 +2477,9 @@ dhd_prot_detach(dhd_pub_t *dhd)
#ifdef PROP_TXSTATUS
dhd_wlfc_deinit(dhd);
#endif
-#ifndef DHD_USE_STATIC_BUF
+#ifndef CONFIG_DHD_USE_STATIC_BUF
MFREE(dhd->osh, dhd->prot, sizeof(dhd_prot_t));
-#endif
+#endif /* CONFIG_DHD_USE_STATIC_BUF */
dhd->prot = NULL;
}
@@ -2512,9 +2515,10 @@ dhd_prot_init(dhd_pub_t *dhd)
ret = dhd_wlfc_init(dhd);
#endif
-#if !defined(WL_CFG80211)
+#if defined(WL_CFG80211)
+ if (dhd_download_fw_on_driverload)
+#endif /* defined(WL_CFG80211) */
ret = dhd_preinit_ioctls(dhd);
-#endif /* WL_CFG80211 */
/* Always assumes wl for now */
dhd->iswl = TRUE;
diff --git a/drivers/net/wireless/bcmdhd/dhd_cfg80211.c b/drivers/net/wireless/bcmdhd/dhd_cfg80211.c
new file mode 100644
index 000000000000..bc1be94802b4
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_cfg80211.c
@@ -0,0 +1,655 @@
+/*
+ * Linux cfg80211 driver - Dongle Host Driver (DHD) related
+ *
+ * Copyright (C) 1999-2011, Broadcom Corporation
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2 (the "GPL"),
+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the
+ * following added to such license:
+ *
+ * As a special exception, the copyright holders of this software give you
+ * permission to link this software with independent modules, and to copy and
+ * distribute the resulting executable under terms of your choice, provided that
+ * you also meet, for each linked independent module, the terms and conditions of
+ * the license of that module. An independent module is a module which is not
+ * derived from this software. The special exception does not apply to any
+ * modifications of the software.
+ *
+ * Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a license
+ * other than the GPL, without Broadcom's express prior written consent.
+ *
+ * $Id: wl_cfg80211.c,v 1.1.4.1.2.14 2011/02/09 01:40:07 Exp $
+ */
+
+#include <net/rtnetlink.h>
+
+#include <bcmutils.h>
+#include <wldev_common.h>
+#include <wl_cfg80211.h>
+#include <dhd_cfg80211.h>
+extern struct wl_priv *wlcfg_drv_priv;
+static int dhd_dongle_up = FALSE;
+
+#include <dngl_stats.h>
+#include <dhd.h>
+#include <dhdioctl.h>
+#include <wlioctl.h>
+#include <dhd_cfg80211.h>
+
+static s32 wl_dongle_up(struct net_device *ndev, u32 up);
+
+/**
+ * Function implementations
+ */
+
+s32 dhd_cfg80211_init(struct wl_priv *wl)
+{
+ dhd_dongle_up = FALSE;
+ return 0;
+}
+
+s32 dhd_cfg80211_deinit(struct wl_priv *wl)
+{
+ dhd_dongle_up = FALSE;
+ return 0;
+}
+
+s32 dhd_cfg80211_get_opmode(struct wl_priv *wl)
+{
+ dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
+ return dhd->op_mode;
+}
+
+s32 dhd_cfg80211_down(struct wl_priv *wl)
+{
+ dhd_dongle_up = FALSE;
+ return 0;
+}
+
+s32 dhd_cfg80211_set_p2p_info(struct wl_priv *wl, int val)
+{
+ dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
+ int bcn_timeout = DHD_BEACON_TIMEOUT_HIGH;
+ char iovbuf[30];
+
+ dhd->op_mode |= val;
+ WL_ERR(("Set : op_mode=%d\n", dhd->op_mode));
+
+#ifdef ARP_OFFLOAD_SUPPORT
+ /* IF P2P is enabled, disable arpoe */
+ dhd_arp_offload_set(dhd, 0);
+ dhd_arp_offload_enable(dhd, false);
+#endif /* ARP_OFFLOAD_SUPPORT */
+
+ dhd_os_set_packet_filter(dhd, 0);
+
+ /* Setup timeout if Beacons are lost and roam is off to report link down */
+ bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+
+
+ return 0;
+}
+
+s32 dhd_cfg80211_clean_p2p_info(struct wl_priv *wl)
+{
+ dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
+ int bcn_timeout = DHD_BEACON_TIMEOUT_NORMAL;
+ char iovbuf[30];
+
+ dhd->op_mode &= ~CONCURENT_MASK;
+ WL_ERR(("Clean : op_mode=%d\n", dhd->op_mode));
+
+#ifdef ARP_OFFLOAD_SUPPORT
+ /* IF P2P is disabled, enable arpoe back for STA mode. */
+ dhd_arp_offload_set(dhd, dhd_arp_mode);
+ dhd_arp_offload_enable(dhd, true);
+#endif /* ARP_OFFLOAD_SUPPORT */
+
+ dhd_os_set_packet_filter(dhd, 1);
+
+ /* Setup timeout if Beacons are lost and roam is off to report link down */
+ bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+
+ return 0;
+}
+
+static s32 wl_dongle_up(struct net_device *ndev, u32 up)
+{
+ s32 err = 0;
+
+ err = wldev_ioctl(ndev, WLC_UP, &up, sizeof(up), true);
+ if (unlikely(err)) {
+ WL_ERR(("WLC_UP error (%d)\n", err));
+ }
+ return err;
+}
+
+s32 dhd_config_dongle(struct wl_priv *wl, bool need_lock)
+{
+#ifndef DHD_SDALIGN
+#define DHD_SDALIGN 32
+#endif
+ struct net_device *ndev;
+ s32 err = 0;
+
+ WL_TRACE(("In\n"));
+ if (dhd_dongle_up) {
+ WL_ERR(("Dongle is already up\n"));
+ return err;
+ }
+
+ ndev = wl_to_prmry_ndev(wl);
+
+ if (need_lock)
+ rtnl_lock();
+
+ err = wl_dongle_up(ndev, 0);
+ if (unlikely(err)) {
+ WL_ERR(("wl_dongle_up failed\n"));
+ goto default_conf_out;
+ }
+ dhd_dongle_up = true;
+
+default_conf_out:
+ if (need_lock)
+ rtnl_unlock();
+ return err;
+
+}
+
+
+/* TODO: clean up the BT-Coex code, it still have some legacy ioctl/iovar functions */
+#define COEX_DHCP
+
+#if defined(COEX_DHCP)
+
+/* use New SCO/eSCO smart YG suppression */
+#define BT_DHCP_eSCO_FIX
+/* this flag boost wifi pkt priority to max, caution: -not fair to sco */
+#define BT_DHCP_USE_FLAGS
+/* T1 start SCO/ESCo priority suppression */
+#define BT_DHCP_OPPR_WIN_TIME 2500
+/* T2 turn off SCO/SCO supperesion is (timeout) */
+#define BT_DHCP_FLAG_FORCE_TIME 5500
+
+enum wl_cfg80211_btcoex_status {
+ BT_DHCP_IDLE,
+ BT_DHCP_START,
+ BT_DHCP_OPPR_WIN,
+ BT_DHCP_FLAG_FORCE_TIMEOUT
+};
+
+/*
+ * get named driver variable to uint register value and return error indication
+ * calling example: dev_wlc_intvar_get_reg(dev, "btc_params",66, &reg_value)
+ */
+static int
+dev_wlc_intvar_get_reg(struct net_device *dev, char *name,
+ uint reg, int *retval)
+{
+ union {
+ char buf[WLC_IOCTL_SMLEN];
+ int val;
+ } var;
+ int error;
+
+ bcm_mkiovar(name, (char *)(&reg), sizeof(reg),
+ (char *)(&var), sizeof(var.buf));
+ error = wldev_ioctl(dev, WLC_GET_VAR, (char *)(&var), sizeof(var.buf), false);
+
+ *retval = dtoh32(var.val);
+ return (error);
+}
+
+static int
+dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
+ char ioctlbuf_local[1024];
+#else
+ static char ioctlbuf_local[1024];
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */
+
+ bcm_mkiovar(name, buf, len, ioctlbuf_local, sizeof(ioctlbuf_local));
+
+ return (wldev_ioctl(dev, WLC_SET_VAR, ioctlbuf_local, sizeof(ioctlbuf_local), true));
+}
+/*
+get named driver variable to uint register value and return error indication
+calling example: dev_wlc_intvar_set_reg(dev, "btc_params",66, value)
+*/
+static int
+dev_wlc_intvar_set_reg(struct net_device *dev, char *name, char *addr, char * val)
+{
+ char reg_addr[8];
+
+ memset(reg_addr, 0, sizeof(reg_addr));
+ memcpy((char *)&reg_addr[0], (char *)addr, 4);
+ memcpy((char *)&reg_addr[4], (char *)val, 4);
+
+ return (dev_wlc_bufvar_set(dev, name, (char *)&reg_addr[0], sizeof(reg_addr)));
+}
+
+static bool btcoex_is_sco_active(struct net_device *dev)
+{
+ int ioc_res = 0;
+ bool res = FALSE;
+ int sco_id_cnt = 0;
+ int param27;
+ int i;
+
+ for (i = 0; i < 12; i++) {
+
+ ioc_res = dev_wlc_intvar_get_reg(dev, "btc_params", 27, &param27);
+
+ WL_TRACE(("%s, sample[%d], btc params: 27:%x\n",
+ __FUNCTION__, i, param27));
+
+ if (ioc_res < 0) {
+ WL_ERR(("%s ioc read btc params error\n", __FUNCTION__));
+ break;
+ }
+
+ if ((param27 & 0x6) == 2) { /* count both sco & esco */
+ sco_id_cnt++;
+ }
+
+ if (sco_id_cnt > 2) {
+ WL_TRACE(("%s, sco/esco detected, pkt id_cnt:%d samples:%d\n",
+ __FUNCTION__, sco_id_cnt, i));
+ res = TRUE;
+ break;
+ }
+
+ msleep(5);
+ }
+
+ return res;
+}
+
+#if defined(BT_DHCP_eSCO_FIX)
+/* Enhanced BT COEX settings for eSCO compatibility during DHCP window */
+static int set_btc_esco_params(struct net_device *dev, bool trump_sco)
+{
+ static bool saved_status = FALSE;
+
+ char buf_reg50va_dhcp_on[8] =
+ { 50, 00, 00, 00, 0x22, 0x80, 0x00, 0x00 };
+ char buf_reg51va_dhcp_on[8] =
+ { 51, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
+ char buf_reg64va_dhcp_on[8] =
+ { 64, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
+ char buf_reg65va_dhcp_on[8] =
+ { 65, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
+ char buf_reg71va_dhcp_on[8] =
+ { 71, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
+ uint32 regaddr;
+ static uint32 saved_reg50;
+ static uint32 saved_reg51;
+ static uint32 saved_reg64;
+ static uint32 saved_reg65;
+ static uint32 saved_reg71;
+
+ if (trump_sco) {
+ /* this should reduce eSCO agressive retransmit
+ * w/o breaking it
+ */
+
+ /* 1st save current */
+ WL_TRACE(("Do new SCO/eSCO coex algo {save &"
+ "override}\n"));
+ if ((!dev_wlc_intvar_get_reg(dev, "btc_params", 50, &saved_reg50)) &&
+ (!dev_wlc_intvar_get_reg(dev, "btc_params", 51, &saved_reg51)) &&
+ (!dev_wlc_intvar_get_reg(dev, "btc_params", 64, &saved_reg64)) &&
+ (!dev_wlc_intvar_get_reg(dev, "btc_params", 65, &saved_reg65)) &&
+ (!dev_wlc_intvar_get_reg(dev, "btc_params", 71, &saved_reg71))) {
+ saved_status = TRUE;
+ WL_TRACE(("%s saved bt_params[50,51,64,65,71]:"
+ "0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ __FUNCTION__, saved_reg50, saved_reg51,
+ saved_reg64, saved_reg65, saved_reg71));
+ } else {
+ WL_ERR((":%s: save btc_params failed\n",
+ __FUNCTION__));
+ saved_status = FALSE;
+ return -1;
+ }
+
+ WL_TRACE(("override with [50,51,64,65,71]:"
+ "0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ *(u32 *)(buf_reg50va_dhcp_on+4),
+ *(u32 *)(buf_reg51va_dhcp_on+4),
+ *(u32 *)(buf_reg64va_dhcp_on+4),
+ *(u32 *)(buf_reg65va_dhcp_on+4),
+ *(u32 *)(buf_reg71va_dhcp_on+4)));
+
+ dev_wlc_bufvar_set(dev, "btc_params",
+ (char *)&buf_reg50va_dhcp_on[0], 8);
+ dev_wlc_bufvar_set(dev, "btc_params",
+ (char *)&buf_reg51va_dhcp_on[0], 8);
+ dev_wlc_bufvar_set(dev, "btc_params",
+ (char *)&buf_reg64va_dhcp_on[0], 8);
+ dev_wlc_bufvar_set(dev, "btc_params",
+ (char *)&buf_reg65va_dhcp_on[0], 8);
+ dev_wlc_bufvar_set(dev, "btc_params",
+ (char *)&buf_reg71va_dhcp_on[0], 8);
+
+ saved_status = TRUE;
+ } else if (saved_status) {
+ /* restore previously saved bt params */
+ WL_TRACE(("Do new SCO/eSCO coex algo {save &"
+ "override}\n"));
+
+ regaddr = 50;
+ dev_wlc_intvar_set_reg(dev, "btc_params",
+ (char *)&regaddr, (char *)&saved_reg50);
+ regaddr = 51;
+ dev_wlc_intvar_set_reg(dev, "btc_params",
+ (char *)&regaddr, (char *)&saved_reg51);
+ regaddr = 64;
+ dev_wlc_intvar_set_reg(dev, "btc_params",
+ (char *)&regaddr, (char *)&saved_reg64);
+ regaddr = 65;
+ dev_wlc_intvar_set_reg(dev, "btc_params",
+ (char *)&regaddr, (char *)&saved_reg65);
+ regaddr = 71;
+ dev_wlc_intvar_set_reg(dev, "btc_params",
+ (char *)&regaddr, (char *)&saved_reg71);
+
+ WL_TRACE(("restore bt_params[50,51,64,65,71]:"
+ "0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ saved_reg50, saved_reg51, saved_reg64,
+ saved_reg65, saved_reg71));
+
+ saved_status = FALSE;
+ } else {
+ WL_ERR((":%s att to restore not saved BTCOEX params\n",
+ __FUNCTION__));
+ return -1;
+ }
+ return 0;
+}
+#endif /* BT_DHCP_eSCO_FIX */
+
+static void
+wl_cfg80211_bt_setflag(struct net_device *dev, bool set)
+{
+#if defined(BT_DHCP_USE_FLAGS)
+ char buf_flag7_dhcp_on[8] = { 7, 00, 00, 00, 0x1, 0x0, 0x00, 0x00 };
+ char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
+#endif
+
+
+#if defined(BT_DHCP_eSCO_FIX)
+ /* set = 1, save & turn on 0 - off & restore prev settings */
+ set_btc_esco_params(dev, set);
+#endif
+
+#if defined(BT_DHCP_USE_FLAGS)
+ WL_TRACE(("WI-FI priority boost via bt flags, set:%d\n", set));
+ if (set == TRUE)
+ /* Forcing bt_flag7 */
+ dev_wlc_bufvar_set(dev, "btc_flags",
+ (char *)&buf_flag7_dhcp_on[0],
+ sizeof(buf_flag7_dhcp_on));
+ else
+ /* Restoring default bt flag7 */
+ dev_wlc_bufvar_set(dev, "btc_flags",
+ (char *)&buf_flag7_default[0],
+ sizeof(buf_flag7_default));
+#endif
+}
+
+static void wl_cfg80211_bt_timerfunc(ulong data)
+{
+ struct btcoex_info *bt_local = (struct btcoex_info *)data;
+ WL_TRACE(("%s\n", __FUNCTION__));
+ bt_local->timer_on = 0;
+ schedule_work(&bt_local->work);
+}
+
+static void wl_cfg80211_bt_handler(struct work_struct *work)
+{
+ struct btcoex_info *btcx_inf;
+
+ btcx_inf = container_of(work, struct btcoex_info, work);
+
+ if (btcx_inf->timer_on) {
+ btcx_inf->timer_on = 0;
+ del_timer_sync(&btcx_inf->timer);
+ }
+
+ switch (btcx_inf->bt_state) {
+ case BT_DHCP_START:
+ /* DHCP started
+ * provide OPPORTUNITY window to get DHCP address
+ */
+ WL_TRACE(("%s bt_dhcp stm: started \n",
+ __FUNCTION__));
+ btcx_inf->bt_state = BT_DHCP_OPPR_WIN;
+ mod_timer(&btcx_inf->timer,
+ jiffies + BT_DHCP_OPPR_WIN_TIME*HZ/1000);
+ btcx_inf->timer_on = 1;
+ break;
+
+ case BT_DHCP_OPPR_WIN:
+ if (btcx_inf->dhcp_done) {
+ WL_TRACE(("%s DHCP Done before T1 expiration\n",
+ __FUNCTION__));
+ goto btc_coex_idle;
+ }
+
+ /* DHCP is not over yet, start lowering BT priority
+ * enforce btc_params + flags if necessary
+ */
+ WL_TRACE(("%s DHCP T1:%d expired\n", __FUNCTION__,
+ BT_DHCP_OPPR_WIN_TIME));
+ if (btcx_inf->dev)
+ wl_cfg80211_bt_setflag(btcx_inf->dev, TRUE);
+ btcx_inf->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT;
+ mod_timer(&btcx_inf->timer,
+ jiffies + BT_DHCP_FLAG_FORCE_TIME*HZ/1000);
+ btcx_inf->timer_on = 1;
+ break;
+
+ case BT_DHCP_FLAG_FORCE_TIMEOUT:
+ if (btcx_inf->dhcp_done) {
+ WL_TRACE(("%s DHCP Done before T2 expiration\n",
+ __FUNCTION__));
+ } else {
+ /* Noo dhcp during T1+T2, restore BT priority */
+ WL_TRACE(("%s DHCP wait interval T2:%d"
+ "msec expired\n", __FUNCTION__,
+ BT_DHCP_FLAG_FORCE_TIME));
+ }
+
+ /* Restoring default bt priority */
+ if (btcx_inf->dev)
+ wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE);
+btc_coex_idle:
+ btcx_inf->bt_state = BT_DHCP_IDLE;
+ btcx_inf->timer_on = 0;
+ break;
+
+ default:
+ WL_ERR(("%s error g_status=%d !!!\n", __FUNCTION__,
+ btcx_inf->bt_state));
+ if (btcx_inf->dev)
+ wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE);
+ btcx_inf->bt_state = BT_DHCP_IDLE;
+ btcx_inf->timer_on = 0;
+ break;
+ }
+
+ net_os_wake_unlock(btcx_inf->dev);
+}
+
+int wl_cfg80211_btcoex_init(struct wl_priv *wl)
+{
+ struct btcoex_info *btco_inf = NULL;
+
+ btco_inf = kmalloc(sizeof(struct btcoex_info), GFP_KERNEL);
+ if (!btco_inf)
+ return -ENOMEM;
+
+ btco_inf->bt_state = BT_DHCP_IDLE;
+ btco_inf->ts_dhcp_start = 0;
+ btco_inf->ts_dhcp_ok = 0;
+ /* Set up timer for BT */
+ btco_inf->timer_ms = 10;
+ init_timer(&btco_inf->timer);
+ btco_inf->timer.data = (ulong)btco_inf;
+ btco_inf->timer.function = wl_cfg80211_bt_timerfunc;
+
+ btco_inf->dev = wl->wdev->netdev;
+
+ INIT_WORK(&btco_inf->work, wl_cfg80211_bt_handler);
+
+ wl->btcoex_info = btco_inf;
+ return 0;
+}
+
+void wl_cfg80211_btcoex_deinit(struct wl_priv *wl)
+{
+ if (!wl->btcoex_info)
+ return;
+
+ if (!wl->btcoex_info->timer_on) {
+ wl->btcoex_info->timer_on = 0;
+ del_timer_sync(&wl->btcoex_info->timer);
+ }
+
+ cancel_work_sync(&wl->btcoex_info->work);
+
+ kfree(wl->btcoex_info);
+ wl->btcoex_info = NULL;
+}
+
+int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command)
+{
+
+ struct wl_priv *wl = wlcfg_drv_priv;
+ char powermode_val = 0;
+ char buf_reg66va_dhcp_on[8] = { 66, 00, 00, 00, 0x10, 0x27, 0x00, 0x00 };
+ char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 };
+ char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 };
+
+ uint32 regaddr;
+ static uint32 saved_reg66;
+ static uint32 saved_reg41;
+ static uint32 saved_reg68;
+ static bool saved_status = FALSE;
+
+#ifdef COEX_DHCP
+ char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
+ struct btcoex_info *btco_inf = wl->btcoex_info;
+#endif /* COEX_DHCP */
+
+ /* Figure out powermode 1 or o command */
+ strncpy((char *)&powermode_val, command + strlen("BTCOEXMODE") +1, 1);
+
+ if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) {
+
+ WL_TRACE(("%s: DHCP session starts\n", __FUNCTION__));
+
+ /* Retrieve and saved orig regs value */
+ if ((saved_status == FALSE) &&
+ (!dev_wlc_intvar_get_reg(dev, "btc_params", 66, &saved_reg66)) &&
+ (!dev_wlc_intvar_get_reg(dev, "btc_params", 41, &saved_reg41)) &&
+ (!dev_wlc_intvar_get_reg(dev, "btc_params", 68, &saved_reg68))) {
+ saved_status = TRUE;
+ WL_TRACE(("Saved 0x%x 0x%x 0x%x\n",
+ saved_reg66, saved_reg41, saved_reg68));
+
+ /* Disable PM mode during dhpc session */
+
+ /* Disable PM mode during dhpc session */
+#ifdef COEX_DHCP
+ /* Start BT timer only for SCO connection */
+ if (btcoex_is_sco_active(dev)) {
+ /* btc_params 66 */
+ dev_wlc_bufvar_set(dev, "btc_params",
+ (char *)&buf_reg66va_dhcp_on[0],
+ sizeof(buf_reg66va_dhcp_on));
+ /* btc_params 41 0x33 */
+ dev_wlc_bufvar_set(dev, "btc_params",
+ (char *)&buf_reg41va_dhcp_on[0],
+ sizeof(buf_reg41va_dhcp_on));
+ /* btc_params 68 0x190 */
+ dev_wlc_bufvar_set(dev, "btc_params",
+ (char *)&buf_reg68va_dhcp_on[0],
+ sizeof(buf_reg68va_dhcp_on));
+ saved_status = TRUE;
+
+ btco_inf->bt_state = BT_DHCP_START;
+ btco_inf->timer_on = 1;
+ mod_timer(&btco_inf->timer, btco_inf->timer.expires);
+ WL_TRACE(("%s enable BT DHCP Timer\n",
+ __FUNCTION__));
+ }
+#endif /* COEX_DHCP */
+ }
+ else if (saved_status == TRUE) {
+ WL_ERR(("%s was called w/o DHCP OFF. Continue\n", __FUNCTION__));
+ }
+ }
+ else if (strnicmp((char *)&powermode_val, "2", strlen("2")) == 0) {
+
+
+ /* Restoring PM mode */
+
+#ifdef COEX_DHCP
+ /* Stop any bt timer because DHCP session is done */
+ WL_TRACE(("%s disable BT DHCP Timer\n", __FUNCTION__));
+ if (btco_inf->timer_on) {
+ btco_inf->timer_on = 0;
+ del_timer_sync(&btco_inf->timer);
+
+ if (btco_inf->bt_state != BT_DHCP_IDLE) {
+ /* need to restore original btc flags & extra btc params */
+ WL_TRACE(("%s bt->bt_state:%d\n",
+ __FUNCTION__, btco_inf->bt_state));
+ /* wake up btcoex thread to restore btlags+params */
+ schedule_work(&btco_inf->work);
+ }
+ }
+
+ /* Restoring btc_flag paramter anyway */
+ if (saved_status == TRUE)
+ dev_wlc_bufvar_set(dev, "btc_flags",
+ (char *)&buf_flag7_default[0], sizeof(buf_flag7_default));
+#endif /* COEX_DHCP */
+
+ /* Restore original values */
+ if (saved_status == TRUE) {
+ regaddr = 66;
+ dev_wlc_intvar_set_reg(dev, "btc_params",
+ (char *)&regaddr, (char *)&saved_reg66);
+ regaddr = 41;
+ dev_wlc_intvar_set_reg(dev, "btc_params",
+ (char *)&regaddr, (char *)&saved_reg41);
+ regaddr = 68;
+ dev_wlc_intvar_set_reg(dev, "btc_params",
+ (char *)&regaddr, (char *)&saved_reg68);
+
+ WL_TRACE(("restore regs {66,41,68} <- 0x%x 0x%x 0x%x\n",
+ saved_reg66, saved_reg41, saved_reg68));
+ }
+ saved_status = FALSE;
+
+ }
+ else {
+ WL_ERR(("%s Unkwown yet power setting, ignored\n",
+ __FUNCTION__));
+ }
+
+ snprintf(command, 3, "OK");
+
+ return (strlen("OK"));
+}
+#endif
diff --git a/drivers/net/wireless/bcmdhd/dhd_cfg80211.h b/drivers/net/wireless/bcmdhd/dhd_cfg80211.h
new file mode 100644
index 000000000000..ced46dbdb96c
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_cfg80211.h
@@ -0,0 +1,45 @@
+/*
+ * Linux cfg80211 driver - Dongle Host Driver (DHD) related
+ *
+ * Copyright (C) 1999-2011, Broadcom Corporation
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2 (the "GPL"),
+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the
+ * following added to such license:
+ *
+ * As a special exception, the copyright holders of this software give you
+ * permission to link this software with independent modules, and to copy and
+ * distribute the resulting executable under terms of your choice, provided that
+ * you also meet, for each linked independent module, the terms and conditions of
+ * the license of that module. An independent module is a module which is not
+ * derived from this software. The special exception does not apply to any
+ * modifications of the software.
+ *
+ * Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a license
+ * other than the GPL, without Broadcom's express prior written consent.
+ *
+ * $Id: wl_cfg80211.c,v 1.1.4.1.2.14 2011/02/09 01:40:07 Exp $
+ */
+
+
+#ifndef __DHD_CFG80211__
+#define __DHD_CFG80211__
+
+#include <wl_cfg80211.h>
+#include <wl_cfgp2p.h>
+
+s32 dhd_cfg80211_init(struct wl_priv *wl);
+s32 dhd_cfg80211_deinit(struct wl_priv *wl);
+s32 dhd_cfg80211_get_opmode(struct wl_priv *wl);
+s32 dhd_cfg80211_down(struct wl_priv *wl);
+s32 dhd_cfg80211_set_p2p_info(struct wl_priv *wl, int val);
+s32 dhd_cfg80211_clean_p2p_info(struct wl_priv *wl);
+s32 dhd_config_dongle(struct wl_priv *wl, bool need_lock);
+
+int wl_cfg80211_btcoex_init(struct wl_priv *wl);
+void wl_cfg80211_btcoex_deinit(struct wl_priv *wl);
+
+#endif /* __DHD_CFG80211__ */
diff --git a/drivers/net/wireless/bcmdhd/dhd_common.c b/drivers/net/wireless/bcmdhd/dhd_common.c
index 372ec80c866a..d9810ace1cb4 100644
--- a/drivers/net/wireless/bcmdhd/dhd_common.c
+++ b/drivers/net/wireless/bcmdhd/dhd_common.c
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: dhd_common.c 290546 2011-10-19 01:55:21Z $
+ * $Id: dhd_common.c 329682 2012-04-26 09:20:38Z $
*/
#include <typedefs.h>
#include <osl.h>
@@ -134,7 +134,7 @@ enum {
};
const bcm_iovar_t dhd_iovars[] = {
- {"version", IOV_VERSION, 0, IOVT_BUFFER, sizeof(dhd_version) },
+ {"version", IOV_VERSION, 0, IOVT_BUFFER, sizeof(dhd_version) },
#ifdef DHD_DEBUG
{"msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 },
#endif /* DHD_DEBUG */
@@ -305,7 +305,7 @@ dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifindex, wl_ioctl_t *ioc, void *buf, int le
dhd_os_proto_block(dhd_pub);
ret = dhd_prot_ioctl(dhd_pub, ifindex, ioc, buf, len);
- if (!ret)
+ if (ret)
dhd_os_check_hang(dhd_pub, ifindex, ret);
dhd_os_proto_unblock(dhd_pub);
@@ -341,6 +341,11 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch
case IOV_SVAL(IOV_MSGLEVEL):
dhd_msg_level = int_val;
+#ifdef WL_CFG80211
+ /* Enable DHD and WL logs in oneshot */
+ if (dhd_msg_level & DHD_WL_VAL)
+ wl_cfg80211_enable_trace(dhd_msg_level);
+#endif
break;
case IOV_GVAL(IOV_BCMERRORSTR):
bcm_strncpy_s((char *)arg, len, bcmerrorstr(dhd_pub->bcmerror), BCME_STRLEN);
@@ -862,6 +867,8 @@ wl_show_host_event(wl_event_msg_t *event, void *event_data)
break;
case WLC_E_SCAN_COMPLETE:
+ case WLC_E_ASSOC_REQ_IE:
+ case WLC_E_ASSOC_RESP_IE:
case WLC_E_PMKID_CACHE:
DHD_EVENT(("MACEVENT: %s\n", event_name));
break;
@@ -994,6 +1001,9 @@ wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata,
datalen = ntoh32_ua((void *)&event->datalen);
evlen = datalen + sizeof(bcm_event_t);
+ DHD_TRACE(("RX: event_type:%d flags:%d status:%d reason:%d \n",
+ type, flags, status, reason));
+
switch (type) {
#ifdef PROP_TXSTATUS
case WLC_E_FIFO_CREDIT_MAP:
@@ -1494,7 +1504,7 @@ dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen)
return -1;
iov_len = bcm_mkiovar("arp_hostip", 0, 0, buf, buflen);
- retcode = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, buflen, TRUE, 0);
+ retcode = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, buflen, FALSE, 0);
if (retcode) {
DHD_TRACE(("%s: ioctl WLC_GET_VAR error %d\n",
@@ -1721,11 +1731,12 @@ fail:
/*
* returns = TRUE if associated, FALSE if not associated
+ * third paramter retval can return error from error
*/
-bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf)
+bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf, int *retval)
{
char bssid[6], zbuf[6];
- int ret = -1;
+ int ret;
bzero(bssid, 6);
bzero(zbuf, 6);
@@ -1733,6 +1744,9 @@ bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf)
ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_BSSID, (char *)&bssid, ETHER_ADDR_LEN, FALSE, 0);
DHD_TRACE((" %s WLC_GET_BSSID ioctl res = %d\n", __FUNCTION__, ret));
+ if (retval)
+ *retval = ret;
+
if (ret == BCME_NOTASSOCIATED) {
DHD_TRACE(("%s: not associated! res:%d\n", __FUNCTION__, ret));
}
@@ -1769,7 +1783,7 @@ dhd_get_dtim_skip(dhd_pub_t *dhd)
bcn_li_dtim = dhd->dtim_skip;
/* Check if associated */
- if (dhd_is_associated(dhd, NULL) == FALSE) {
+ if (dhd_is_associated(dhd, NULL, NULL) == FALSE) {
DHD_TRACE(("%s NOT assoc ret %d\n", __FUNCTION__, ret));
goto exit;
}
@@ -1812,10 +1826,24 @@ exit:
bool dhd_check_ap_wfd_mode_set(dhd_pub_t *dhd)
{
#ifdef WL_CFG80211
+#ifndef WL_ENABLE_P2P_IF
+ /* To be back compatble with ICS MR1 release where p2p interface
+ * disable but wlan0 used for p2p
+ */
if (((dhd->op_mode & HOSTAPD_MASK) == HOSTAPD_MASK) ||
- ((dhd->op_mode & WFD_MASK) == WFD_MASK))
+ ((dhd->op_mode & WFD_MASK) == WFD_MASK)) {
return TRUE;
+ }
else
+#else
+ /* concurent mode with p2p interface for wfd and wlan0 for sta */
+ if (((dhd->op_mode & P2P_GO_ENABLED) == P2P_GO_ENABLED) ||
+ ((dhd->op_mode & P2P_GC_ENABLED) == P2P_GC_ENABLED)) {
+ DHD_ERROR(("%s P2P enabled for mode=%d\n", __FUNCTION__, dhd->op_mode));
+ return TRUE;
+ }
+ else
+#endif /* WL_ENABLE_P2P_IF */
#endif /* WL_CFG80211 */
return FALSE;
}
@@ -1867,10 +1895,12 @@ dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled)
memset(iovbuf, 0, sizeof(iovbuf));
- if ((pfn_enabled) && (dhd_is_associated(dhd, NULL) == TRUE)) {
+#ifndef WL_SCHED_SCAN
+ if ((pfn_enabled) && (dhd_is_associated(dhd, NULL, NULL) == TRUE)) {
DHD_ERROR(("%s pno is NOT enable : called in assoc mode , ignore\n", __FUNCTION__));
return ret;
}
+#endif /* !WL_SCHED_SCAN */
/* Enable/disable PNO */
if ((ret = bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf))) > 0) {
@@ -1907,6 +1937,7 @@ dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr,
if ((!dhd) && (!ssids_local)) {
DHD_ERROR(("%s error exit\n", __FUNCTION__));
err = -1;
+ return err;
}
if (dhd_check_ap_wfd_mode_set(dhd) == TRUE)
@@ -2056,6 +2087,7 @@ int dhd_keep_alive_onoff(dhd_pub_t *dhd)
return res;
}
#endif /* defined(KEEP_ALIVE) */
+
/* Android ComboSCAN support */
/*
@@ -2160,14 +2192,14 @@ wl_iw_parse_channel_list_tlv(char** list_str, uint16* channel_list,
int
wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_t* ssid, int max, int *bytes_left)
{
- char* str = *list_str;
+ char* str;
int idx = 0;
if ((list_str == NULL) || (*list_str == NULL) || (*bytes_left < 0)) {
DHD_ERROR(("%s error paramters\n", __FUNCTION__));
return -1;
}
-
+ str = *list_str;
while (*bytes_left > 0) {
if (str[0] != CSCAN_TLV_TYPE_SSID_IE) {
diff --git a/drivers/net/wireless/bcmdhd/dhd_dbg.h b/drivers/net/wireless/bcmdhd/dhd_dbg.h
index a195cbe88e5b..01be6a1f056f 100644
--- a/drivers/net/wireless/bcmdhd/dhd_dbg.h
+++ b/drivers/net/wireless/bcmdhd/dhd_dbg.h
@@ -29,8 +29,8 @@
#if defined(DHD_DEBUG)
-#define DHD_ERROR(args) do {if ((dhd_msg_level & DHD_ERROR_VAL) && (net_ratelimit())) \
- printf args;} while (0)
+#define DHD_ERROR(args) do {if ((dhd_msg_level & DHD_ERROR_VAL) && (net_ratelimit())) \
+ printf args;} while (0)
#define DHD_TRACE(args) do {if (dhd_msg_level & DHD_TRACE_VAL) printf args;} while (0)
#define DHD_INFO(args) do {if (dhd_msg_level & DHD_INFO_VAL) printf args;} while (0)
#define DHD_DATA(args) do {if (dhd_msg_level & DHD_DATA_VAL) printf args;} while (0)
diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c
index 80a75699e270..6ba7df1cac32 100644
--- a/drivers/net/wireless/bcmdhd/dhd_linux.c
+++ b/drivers/net/wireless/bcmdhd/dhd_linux.c
@@ -22,7 +22,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: dhd_linux.c 291449 2011-10-22 12:16:26Z $
+ * $Id: dhd_linux.c 329682 2012-04-26 09:20:38Z $
*/
#include <typedefs.h>
@@ -50,6 +50,7 @@
#include <epivers.h>
#include <bcmutils.h>
#include <bcmendian.h>
+#include <bcmdevs.h>
#include <proto/ethernet.h>
#include <dngl_stats.h>
@@ -110,6 +111,7 @@ extern bool ap_fw_loaded;
#include <wl_android.h>
#ifdef ARP_OFFLOAD_SUPPORT
+void aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add);
static int dhd_device_event(struct notifier_block *this,
unsigned long event,
void *ptr);
@@ -128,6 +130,9 @@ DECLARE_WAIT_QUEUE_HEAD(dhd_dpc_wait);
#if defined(OOB_INTR_ONLY)
extern void dhd_enable_oob_intr(struct dhd_bus *bus, bool enable);
#endif /* defined(OOB_INTR_ONLY) */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+static void dhd_hang_process(struct work_struct *work);
+#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
MODULE_LICENSE("GPL v2");
#endif /* LinuxVer */
@@ -154,11 +159,10 @@ print_tainted()
extern wl_iw_extra_params_t g_wl_iw_params;
#endif /* defined(CONFIG_BCMDHD_WEXT) */
-#if defined(CONFIG_HAS_EARLYSUSPEND)
+#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
#include <linux/earlysuspend.h>
-extern int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len);
-extern int dhd_get_dtim_skip(dhd_pub_t *dhd);
#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */
+extern int dhd_get_dtim_skip(dhd_pub_t *dhd);
#ifdef PKT_FILTER_SUPPORT
extern void dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg);
@@ -247,11 +251,15 @@ typedef struct dhd_info {
bool dhd_tasklet_create;
#endif /* DHDTHREAD */
tsk_ctl_t thr_sysioc_ctl;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+ struct work_struct work_hang;
+#endif
/* Wakelocks */
#if defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
struct wake_lock wl_wifi; /* Wifi wakelock */
struct wake_lock wl_rxwake; /* Wifi rx wakelock */
+ struct wake_lock wl_ctrlwake; /* Wifi ctrl wakelock */
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
@@ -259,10 +267,12 @@ typedef struct dhd_info {
* calls and wifi_on or wifi_off
*/
struct mutex dhd_net_if_mutex;
+ struct mutex dhd_suspend_mutex;
#endif
spinlock_t wakelock_spinlock;
int wakelock_counter;
- int wakelock_timeout_enable;
+ int wakelock_rx_timeout_enable;
+ int wakelock_ctrl_timeout_enable;
/* Thread to issue ioctl for multicast */
bool set_macaddress;
@@ -271,9 +281,13 @@ typedef struct dhd_info {
atomic_t pend_8021x_cnt;
dhd_attach_states_t dhd_state;
-#ifdef CONFIG_HAS_EARLYSUSPEND
+#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
struct early_suspend early_suspend;
#endif /* CONFIG_HAS_EARLYSUSPEND */
+
+#ifdef ARP_OFFLOAD_SUPPORT
+ u32 pend_ipaddr;
+#endif /* ARP_OFFLOAD_SUPPORT */
} dhd_info_t;
/* Definitions to provide path to the firmware and nvram
@@ -282,6 +296,8 @@ typedef struct dhd_info {
char firmware_path[MOD_PARAM_PATHLEN];
char nvram_path[MOD_PARAM_PATHLEN];
+int op_mode = 0;
+module_param(op_mode, int, 0644);
extern int wl_control_wl_start(struct net_device *dev);
extern int net_os_send_hang_message(struct net_device *dev);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
@@ -353,25 +369,6 @@ uint dhd_radio_up = 1;
char iface_name[IFNAMSIZ] = {'\0'};
module_param_string(iface_name, iface_name, IFNAMSIZ, 0);
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
-#define DAEMONIZE(a) daemonize(a); \
- allow_signal(SIGKILL); \
- allow_signal(SIGTERM);
-#else /* Linux 2.4 (w/o preemption patch) */
-#define RAISE_RX_SOFTIRQ() \
- cpu_raise_softirq(smp_processor_id(), NET_RX_SOFTIRQ)
-#define DAEMONIZE(a) daemonize(); \
- do { if (a) \
- strncpy(current->comm, a, MIN(sizeof(current->comm), (strlen(a) + 1))); \
- } while (0);
-#endif /* LINUX_VERSION_CODE */
-
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
-#define BLOCKABLE() (!in_atomic())
-#else
-#define BLOCKABLE() (!in_interrupt())
-#endif
-
/* The following are specific to the SDIO dongle */
/* IOCTL response timeout */
@@ -437,6 +434,11 @@ static char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR
;
static void dhd_net_if_lock_local(dhd_info_t *dhd);
static void dhd_net_if_unlock_local(dhd_info_t *dhd);
+static void dhd_suspend_lock(dhd_pub_t *dhdp);
+static void dhd_suspend_unlock(dhd_pub_t *dhdp);
+#if !defined(AP) && defined(WLP2P) && defined(WL_ENABLE_P2P_IF)
+static u32 dhd_concurrent_fw(dhd_pub_t *dhd);
+#endif
#ifdef WLMEDIA_HTSF
void htsf_update(dhd_info_t *dhd, void *data);
@@ -479,7 +481,7 @@ static int dhd_sleep_pm_callback(struct notifier_block *nfb, unsigned long actio
{
int ret = NOTIFY_DONE;
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39))
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39))
switch (action) {
case PM_HIBERNATION_PREPARE:
case PM_SUSPEND_PREPARE:
@@ -499,7 +501,7 @@ static int dhd_sleep_pm_callback(struct notifier_block *nfb, unsigned long actio
static struct notifier_block dhd_sleep_pm_notifier = {
.notifier_call = dhd_sleep_pm_callback,
- .priority = 0
+ .priority = 10
};
extern int register_pm_notifier(struct notifier_block *nb);
extern int unregister_pm_notifier(struct notifier_block *nb);
@@ -511,7 +513,8 @@ static void dhd_set_packet_filter(int value, dhd_pub_t *dhd)
DHD_TRACE(("%s: %d\n", __FUNCTION__, value));
/* 1 - Enable packet filter, only allow unicast packet to send up */
/* 0 - Disable packet filter */
- if (dhd_pkt_filter_enable) {
+ if (dhd_pkt_filter_enable && (!value ||
+ (dhd_check_ap_wfd_mode_set(dhd) == FALSE))) {
int i;
for (i = 0; i < dhd->pktfilter_count; i++) {
@@ -523,7 +526,6 @@ static void dhd_set_packet_filter(int value, dhd_pub_t *dhd)
#endif
}
-#if defined(CONFIG_HAS_EARLYSUSPEND)
static int dhd_set_suspend(int value, dhd_pub_t *dhd)
{
int power_mode = PM_MAX;
@@ -535,70 +537,76 @@ static int dhd_set_suspend(int value, dhd_pub_t *dhd)
DHD_TRACE(("%s: enter, value = %d in_suspend=%d\n",
__FUNCTION__, value, dhd->in_suspend));
+ dhd_suspend_lock(dhd);
if (dhd && dhd->up) {
if (value && dhd->in_suspend) {
- /* Kernel suspended */
- DHD_ERROR(("%s: force extra Suspend setting \n", __FUNCTION__));
-
- dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode,
- sizeof(power_mode), TRUE, 0);
+ /* Kernel suspended */
+ DHD_ERROR(("%s: force extra Suspend setting \n", __FUNCTION__));
- /* Enable packet filter, only allow unicast packet to send up */
- dhd_set_packet_filter(1, dhd);
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode,
+ sizeof(power_mode), TRUE, 0);
- /* If DTIM skip is set up as default, force it to wake
- * each third DTIM for better power savings. Note that
- * one side effect is a chance to miss BC/MC packet.
- */
- bcn_li_dtim = dhd_get_dtim_skip(dhd);
- bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim,
- 4, iovbuf, sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ /* Enable packet filter, only allow unicast packet to send up */
+ dhd_set_packet_filter(1, dhd);
- /* Disable firmware roaming during suspend */
- bcm_mkiovar("roam_off", (char *)&roamvar, 4,
- iovbuf, sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
- } else {
+ /* If DTIM skip is set up as default, force it to wake
+ * each third DTIM for better power savings. Note that
+ * one side effect is a chance to miss BC/MC packet.
+ */
+ bcn_li_dtim = dhd_get_dtim_skip(dhd);
+ bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim,
+ 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+
+ /* Disable firmware roaming during suspend */
+ bcm_mkiovar("roam_off", (char *)&roamvar, 4,
+ iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ } else {
- /* Kernel resumed */
- DHD_TRACE(("%s: Remove extra suspend setting \n", __FUNCTION__));
+ /* Kernel resumed */
+ DHD_TRACE(("%s: Remove extra suspend setting \n", __FUNCTION__));
- power_mode = PM_FAST;
- dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode,
- sizeof(power_mode), TRUE, 0);
+ power_mode = PM_FAST;
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode,
+ sizeof(power_mode), TRUE, 0);
- /* disable pkt filter */
- dhd_set_packet_filter(0, dhd);
+ /* disable pkt filter */
+ dhd_set_packet_filter(0, dhd);
- /* restore pre-suspend setting for dtim_skip */
- bcm_mkiovar("bcn_li_dtim", (char *)&dhd->dtim_skip,
- 4, iovbuf, sizeof(iovbuf));
+ /* restore pre-suspend setting for dtim_skip */
+ bcm_mkiovar("bcn_li_dtim", (char *)&dhd->dtim_skip,
+ 4, iovbuf, sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
- roamvar = dhd_roam_disable;
- bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf,
- sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
- }
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ roamvar = dhd_roam_disable;
+ bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf,
+ sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ }
}
-
+ dhd_suspend_unlock(dhd);
return 0;
}
-static void dhd_suspend_resume_helper(struct dhd_info *dhd, int val)
+static int dhd_suspend_resume_helper(struct dhd_info *dhd, int val, int force)
{
dhd_pub_t *dhdp = &dhd->pub;
+ int ret = 0;
DHD_OS_WAKE_LOCK(dhdp);
/* Set flag when early suspend was called */
dhdp->in_suspend = val;
- if ((!dhdp->suspend_disable_flag) && (dhd_check_ap_wfd_mode_set(dhdp) == FALSE))
- dhd_set_suspend(val, dhdp);
+ if ((force || !dhdp->suspend_disable_flag) &&
+ (dhd_check_ap_wfd_mode_set(dhdp) == FALSE)) {
+ ret = dhd_set_suspend(val, dhdp);
+ }
DHD_OS_WAKE_UNLOCK(dhdp);
+ return ret;
}
+#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
static void dhd_early_suspend(struct early_suspend *h)
{
struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend);
@@ -606,7 +614,7 @@ static void dhd_early_suspend(struct early_suspend *h)
DHD_TRACE(("%s: enter\n", __FUNCTION__));
if (dhd)
- dhd_suspend_resume_helper(dhd, 1);
+ dhd_suspend_resume_helper(dhd, 1, 0);
}
static void dhd_late_resume(struct early_suspend *h)
@@ -616,7 +624,7 @@ static void dhd_late_resume(struct early_suspend *h)
DHD_TRACE(("%s: enter\n", __FUNCTION__));
if (dhd)
- dhd_suspend_resume_helper(dhd, 0);
+ dhd_suspend_resume_helper(dhd, 0, 0);
}
#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */
@@ -664,16 +672,12 @@ dhd_timeout_expired(dhd_timeout_t *tmo)
} else {
wait_queue_head_t delay_wait;
DECLARE_WAITQUEUE(wait, current);
- int pending;
init_waitqueue_head(&delay_wait);
add_wait_queue(&delay_wait, &wait);
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(1);
- pending = signal_pending(current);
remove_wait_queue(&delay_wait, &wait);
set_current_state(TASK_RUNNING);
- if (pending)
- return 1; /* Interrupted */
}
return 0;
@@ -694,8 +698,9 @@ dhd_net2idx(dhd_info_t *dhd, struct net_device *net)
return DHD_BAD_IF;
}
-struct net_device * dhd_idx2net(struct dhd_pub *dhd_pub, int ifidx)
+struct net_device * dhd_idx2net(void *pub, int ifidx)
{
+ struct dhd_pub *dhd_pub = (struct dhd_pub *)pub;
struct dhd_info *dhd_info;
if (!dhd_pub || ifidx < 0 || ifidx >= DHD_MAX_IFS)
@@ -923,6 +928,7 @@ _dhd_set_mac_address(dhd_info_t *dhd, int ifidx, struct ether_addr *addr)
DHD_ERROR(("%s: set cur_etheraddr failed\n", dhd_ifname(&dhd->pub, ifidx)));
} else {
memcpy(dhd->iflist[ifidx]->net->dev_addr, addr, ETHER_ADDR_LEN);
+ memcpy(dhd->pub.mac.octet, addr, ETHER_ADDR_LEN);
}
return ret;
@@ -942,8 +948,9 @@ dhd_op_if(dhd_if_t *ifp)
unsigned long flags;
#endif
+ if (!ifp || !ifp->info || !ifp->idx)
+ return;
ASSERT(ifp && ifp->info && ifp->idx); /* Virtual interfaces only */
-
dhd = ifp->info;
DHD_TRACE(("%s: idx %d, state %d\n", __FUNCTION__, ifp->idx, ifp->state));
@@ -978,7 +985,7 @@ dhd_op_if(dhd_if_t *ifp)
#ifdef WL_CFG80211
if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)
if (!wl_cfg80211_notify_ifadd(ifp->net, ifp->idx, ifp->bssidx,
- dhd_net_attach)) {
+ (void*)dhd_net_attach)) {
ifp->state = DHD_IF_NONE;
return;
}
@@ -1014,12 +1021,18 @@ dhd_op_if(dhd_if_t *ifp)
DHD_TRACE(("\n%s: got 'DHD_IF_DEL' state\n", __FUNCTION__));
#ifdef WL_CFG80211
if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) {
- wl_cfg80211_notify_ifdel(ifp->net);
+ wl_cfg80211_ifdel_ops(ifp->net);
}
#endif
netif_stop_queue(ifp->net);
unregister_netdev(ifp->net);
- ret = DHD_DEL_IF; /* Make sure the free_netdev() is called */
+ ret = DHD_DEL_IF;
+
+#ifdef WL_CFG80211
+ if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) {
+ wl_cfg80211_notify_ifdel();
+ }
+#endif
}
break;
case DHD_IF_DELETING:
@@ -1034,6 +1047,7 @@ dhd_op_if(dhd_if_t *ifp)
ifp->set_multicast = FALSE;
if (ifp->net) {
free_netdev(ifp->net);
+ ifp->net = NULL;
}
dhd->iflist[ifp->idx] = NULL;
#ifdef SOFTAP
@@ -1135,7 +1149,7 @@ dhd_set_mac_address(struct net_device *dev, void *addr)
if (ifidx == DHD_BAD_IF)
return -1;
- ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0);
+ ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0);
memcpy(&dhd->macvalue, sa->sa_data, ETHER_ADDR_LEN);
dhd->set_macaddress = TRUE;
up(&dhd->thr_sysioc_ctl.sema);
@@ -1153,7 +1167,7 @@ dhd_set_multicast_list(struct net_device *dev)
if (ifidx == DHD_BAD_IF)
return;
- ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0);
+ ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0);
dhd->iflist[ifidx]->set_multicast = TRUE;
up(&dhd->thr_sysioc_ctl.sema);
}
@@ -1164,6 +1178,7 @@ dhd_os_wlfc_block(dhd_pub_t *pub)
{
dhd_info_t *di = (dhd_info_t *)(pub->info);
ASSERT(di != NULL);
+
spin_lock_bh(&di->wlfc_spinlock);
return 1;
}
@@ -1197,7 +1212,7 @@ dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf)
}
/* Update multicast statistic */
- if (PKTLEN(dhdp->osh, pktbuf) >= ETHER_ADDR_LEN) {
+ if (PKTLEN(dhdp->osh, pktbuf) >= ETHER_HDR_LEN) {
uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, pktbuf);
eh = (struct ether_header *)pktdata;
@@ -1205,6 +1220,9 @@ dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf)
dhdp->tx_multicast++;
if (ntoh16(eh->ether_type) == ETHER_TYPE_802_1X)
atomic_inc(&dhd->pend_8021x_cnt);
+ } else {
+ PKTFREE(dhd->pub.osh, pktbuf, TRUE);
+ return BCME_ERROR;
}
/* Look into the packet and update the packet priority */
@@ -1280,11 +1298,13 @@ dhd_start_xmit(struct sk_buff *skb, struct net_device *net)
DHD_ERROR(("%s: xmit rejected pub.up=%d busstate=%d \n",
__FUNCTION__, dhd->pub.up, dhd->pub.busstate));
netif_stop_queue(net);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
/* Send Event when bus down detected during data session */
if (dhd->pub.busstate == DHD_BUS_DOWN) {
DHD_ERROR(("%s: Event HANG sent up\n", __FUNCTION__));
net_os_send_hang_message(net);
}
+#endif
DHD_OS_WAKE_UNLOCK(&dhd->pub);
return -ENODEV;
}
@@ -1398,7 +1418,8 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
int i;
dhd_if_t *ifp;
wl_event_msg_t event;
- int tout = DHD_PACKET_TIMEOUT;
+ int tout_rx = 0;
+ int tout_ctrl = 0;
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
@@ -1415,7 +1436,7 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
PKTFREE(dhdp->osh, pktbuf, TRUE);
continue;
}
-
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
/* Dropping packets before registering net device to avoid kernel panic */
if (!ifp->net || ifp->net->reg_state != NETREG_REGISTERED ||
!dhd->pub.up) {
@@ -1424,6 +1445,7 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
PKTFREE(dhdp->osh, pktbuf, TRUE);
continue;
}
+#endif
pnext = PKTNEXT(dhdp->osh, pktbuf);
PKTSETNEXT(wl->sh.osh, pktbuf, NULL);
@@ -1448,6 +1470,7 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
*/
((athost_wl_status_info_t*)dhdp->wlfc_state)->stats.wlfc_header_only_pkt++;
PKTFREE(dhdp->osh, pktbuf, TRUE);
+ DHD_TRACE(("RX: wlfc header \n"));
continue;
}
#endif
@@ -1499,10 +1522,15 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
&data);
wl_event_to_host_order(&event);
+ if (!tout_ctrl)
+ tout_ctrl = DHD_PACKET_TIMEOUT_MS;
if (event.event_type == WLC_E_BTA_HCI_EVENT) {
dhd_bta_doevt(dhdp, data, event.datalen);
+ } else if (event.event_type == WLC_E_PFN_NET_FOUND) {
+ tout_ctrl *= 2;
}
- tout = DHD_EVENT_TIMEOUT;
+ } else {
+ tout_rx = DHD_PACKET_TIMEOUT_MS;
}
ASSERT(ifidx < DHD_MAX_IFS && dhd->iflist[ifidx]);
@@ -1535,7 +1563,8 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */
}
}
- DHD_OS_WAKE_LOCK_TIMEOUT_ENABLE(dhdp, tout);
+ DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(dhdp, tout_rx);
+ DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhdp, tout_ctrl);
}
void
@@ -1589,8 +1618,10 @@ dhd_get_stats(struct net_device *net)
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
ifidx = dhd_net2idx(dhd, net);
- if (ifidx == DHD_BAD_IF)
+ if (ifidx == DHD_BAD_IF) {
+ DHD_ERROR(("%s: BAD_IF\n", __FUNCTION__));
return NULL;
+ }
ifp = dhd->iflist[ifidx];
ASSERT(dhd && ifp);
@@ -2001,6 +2032,7 @@ dhd_ethtool(dhd_info_t *dhd, void *uaddr)
static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error)
{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
if (!dhdp)
return FALSE;
if ((error == -ETIMEDOUT) || ((dhdp->busstate == DHD_BUS_DOWN) &&
@@ -2010,6 +2042,7 @@ static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error)
net_os_send_hang_message(net);
return TRUE;
}
+#endif
return FALSE;
}
@@ -2030,7 +2063,7 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd)
/* send to dongle only if we are not waiting for reload already */
if (dhd->pub.hang_was_sent) {
DHD_ERROR(("%s: HANG was sent up earlier\n", __FUNCTION__));
- DHD_OS_WAKE_LOCK_TIMEOUT_ENABLE(&dhd->pub, DHD_EVENT_TIMEOUT);
+ DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(&dhd->pub, DHD_EVENT_TIMEOUT_MS);
DHD_OS_WAKE_UNLOCK(&dhd->pub);
return OSL_ERROR(BCME_DONGLE_DOWN);
}
@@ -2039,6 +2072,7 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd)
DHD_TRACE(("%s: ifidx %d, cmd 0x%04x\n", __FUNCTION__, ifidx, cmd));
if (ifidx == DHD_BAD_IF) {
+ DHD_ERROR(("%s: BAD IF\n", __FUNCTION__));
DHD_OS_WAKE_UNLOCK(&dhd->pub);
return -1;
}
@@ -2236,6 +2270,7 @@ dhd_cleanup_virt_ifaces(dhd_info_t *dhd)
#endif
for (i = 1; i < DHD_MAX_IFS; i++) {
+ dhd_net_if_lock_local(dhd);
if (dhd->iflist[i]) {
DHD_TRACE(("Deleting IF: %d \n", i));
if ((dhd->iflist[i]->state != DHD_IF_DEL) &&
@@ -2245,6 +2280,7 @@ dhd_cleanup_virt_ifaces(dhd_info_t *dhd)
dhd_op_if(dhd->iflist[i]);
}
}
+ dhd_net_if_unlock_local(dhd);
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
@@ -2259,10 +2295,10 @@ dhd_cleanup_virt_ifaces(dhd_info_t *dhd)
static int
dhd_stop(struct net_device *net)
{
- int ifidx;
+ int ifidx = 0;
dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net);
DHD_OS_WAKE_LOCK(&dhd->pub);
- DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+ DHD_TRACE(("%s: Enter %p\n", __FUNCTION__, net));
if (dhd->pub.up == 0) {
goto exit;
}
@@ -2270,7 +2306,7 @@ dhd_stop(struct net_device *net)
#ifdef WL_CFG80211
if (ifidx == 0) {
- wl_cfg80211_down();
+ wl_cfg80211_down(NULL);
/*
* For CFG80211: Clean up all the left over virtual interfaces
@@ -2293,15 +2329,15 @@ dhd_stop(struct net_device *net)
/* Stop the protocol module */
dhd_prot_stop(&dhd->pub);
+ OLD_MOD_DEC_USE_COUNT;
+exit:
#if defined(WL_CFG80211)
if (ifidx == 0 && !dhd_download_fw_on_driverload)
wl_android_wifi_off(net);
#endif
- dhd->pub.hang_was_sent = 0;
dhd->pub.rxcnt_timeout = 0;
dhd->pub.txcnt_timeout = 0;
- OLD_MOD_DEC_USE_COUNT;
-exit:
+
DHD_OS_WAKE_UNLOCK(&dhd->pub);
return 0;
}
@@ -2326,13 +2362,19 @@ dhd_open(struct net_device *net)
firmware_path[0] = '\0';
}
+ dhd->pub.hang_was_sent = 0;
#if !defined(WL_CFG80211)
/*
* Force start if ifconfig_up gets called before START command
* We keep WEXT's wl_control_wl_start to provide backward compatibility
* This should be removed in the future
*/
- wl_control_wl_start(net);
+ ret = wl_control_wl_start(net);
+ if (ret != 0) {
+ DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret));
+ ret = -1;
+ goto exit;
+ }
#endif
ifidx = dhd_net2idx(dhd, net);
@@ -2354,12 +2396,17 @@ dhd_open(struct net_device *net)
atomic_set(&dhd->pend_8021x_cnt, 0);
#if defined(WL_CFG80211)
DHD_ERROR(("\n%s\n", dhd_version));
- if (!dhd_download_fw_on_driverload)
- wl_android_wifi_on(net);
+ if (!dhd_download_fw_on_driverload) {
+ ret = wl_android_wifi_on(net);
+ if (ret != 0) {
+ DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret));
+ ret = -1;
+ goto exit;
+ }
+ }
#endif /* defined(WL_CFG80211) */
if (dhd->pub.busstate != DHD_BUS_DATA) {
- int ret;
/* try to bring up bus */
if ((ret = dhd_bus_start(&dhd->pub)) != 0) {
@@ -2382,7 +2429,7 @@ dhd_open(struct net_device *net)
#endif /* TOE */
#if defined(WL_CFG80211)
- if (unlikely(wl_cfg80211_up())) {
+ if (unlikely(wl_cfg80211_up(NULL))) {
DHD_ERROR(("%s: failed to bring up cfg80211\n", __FUNCTION__));
ret = -1;
goto exit;
@@ -2400,10 +2447,39 @@ dhd_open(struct net_device *net)
OLD_MOD_INC_USE_COUNT;
exit:
+ if (ret)
+ dhd_stop(net);
+
DHD_OS_WAKE_UNLOCK(&dhd->pub);
return ret;
}
+int dhd_do_driver_init(struct net_device *net)
+{
+ dhd_info_t *dhd = NULL;
+
+ if (!net) {
+ DHD_ERROR(("Primary Interface not initialized \n"));
+ return -EINVAL;
+ }
+
+ dhd = *(dhd_info_t **)netdev_priv(net);
+
+ /* If driver is already initialized, do nothing
+ */
+ if (dhd->pub.busstate == DHD_BUS_DATA) {
+ DHD_TRACE(("Driver already Inititalized. Nothing to do"));
+ return 0;
+ }
+
+ if (dhd_open(net) < 0) {
+ DHD_ERROR(("Driver Init Failed \n"));
+ return -1;
+ }
+
+ return 0;
+}
+
osl_t *
dhd_osl_attach(void *pdev, uint bustype)
{
@@ -2457,7 +2533,7 @@ dhd_add_if(dhd_info_t *dhd, int ifidx, void *handle, char *name,
ifp->state = DHD_IF_ADD;
ifp->idx = ifidx;
ifp->bssidx = bssidx;
- ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0);
+ ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0);
up(&dhd->thr_sysioc_ctl.sema);
} else
ifp->net = (struct net_device *)handle;
@@ -2481,10 +2557,30 @@ dhd_del_if(dhd_info_t *dhd, int ifidx)
ifp->state = DHD_IF_DEL;
ifp->idx = ifidx;
- ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0);
+ ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0);
up(&dhd->thr_sysioc_ctl.sema);
}
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
+static struct net_device_ops dhd_ops_pri = {
+ .ndo_open = dhd_open,
+ .ndo_stop = dhd_stop,
+ .ndo_get_stats = dhd_get_stats,
+ .ndo_do_ioctl = dhd_ioctl_entry,
+ .ndo_start_xmit = dhd_start_xmit,
+ .ndo_set_mac_address = dhd_set_mac_address,
+ .ndo_set_multicast_list = dhd_set_multicast_list,
+};
+
+static struct net_device_ops dhd_ops_virt = {
+ .ndo_get_stats = dhd_get_stats,
+ .ndo_do_ioctl = dhd_ioctl_entry,
+ .ndo_start_xmit = dhd_start_xmit,
+ .ndo_set_mac_address = dhd_set_mac_address,
+ .ndo_set_multicast_list = dhd_set_multicast_list,
+};
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) */
+
dhd_pub_t *
dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen, void *dev)
{
@@ -2577,13 +2673,16 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen, void *dev)
/* Initialize Wakelock stuff */
spin_lock_init(&dhd->wakelock_spinlock);
dhd->wakelock_counter = 0;
- dhd->wakelock_timeout_enable = 0;
+ dhd->wakelock_rx_timeout_enable = 0;
+ dhd->wakelock_ctrl_timeout_enable = 0;
#ifdef CONFIG_HAS_WAKELOCK
wake_lock_init(&dhd->wl_wifi, WAKE_LOCK_SUSPEND, "wlan_wake");
wake_lock_init(&dhd->wl_rxwake, WAKE_LOCK_SUSPEND, "wlan_rx_wake");
+ wake_lock_init(&dhd->wl_ctrlwake, WAKE_LOCK_SUSPEND, "wlan_ctrl_wake");
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
mutex_init(&dhd->dhd_net_if_mutex);
+ mutex_init(&dhd->dhd_suspend_mutex);
#endif
dhd_state |= DHD_ATTACH_STATE_WAKELOCKS_INIT;
@@ -2659,7 +2758,9 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen, void *dev)
dhd->thr_sysioc_ctl.thr_pid = -1;
}
dhd_state |= DHD_ATTACH_STATE_THREADS_CREATED;
-
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+ INIT_WORK(&dhd->work_hang, dhd_hang_process);
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
/*
* Save the dhd_info into the priv
*/
@@ -2669,7 +2770,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen, void *dev)
register_pm_notifier(&dhd_sleep_pm_notifier);
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */
-#ifdef CONFIG_HAS_EARLYSUSPEND
+#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
dhd->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 20;
dhd->early_suspend.suspend = dhd_early_suspend;
dhd->early_suspend.resume = dhd_late_resume;
@@ -2678,6 +2779,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen, void *dev)
#endif
#ifdef ARP_OFFLOAD_SUPPORT
+ dhd->pend_ipaddr = 0;
register_inetaddr_notifier(&dhd_notifier);
#endif /* ARP_OFFLOAD_SUPPORT */
@@ -2711,7 +2813,8 @@ dhd_bus_start(dhd_pub_t *dhdp)
DHD_TRACE(("Enter %s:\n", __FUNCTION__));
#ifdef DHDTHREAD
- dhd_os_sdlock(dhdp);
+ if (dhd->threads_only)
+ dhd_os_sdlock(dhdp);
#endif /* DHDTHREAD */
/* try to download image and nvram to the dongle */
@@ -2724,14 +2827,16 @@ dhd_bus_start(dhd_pub_t *dhdp)
DHD_ERROR(("%s: dhdsdio_probe_download failed. firmware = %s nvram = %s\n",
__FUNCTION__, fw_path, nv_path));
#ifdef DHDTHREAD
- dhd_os_sdunlock(dhdp);
+ if (dhd->threads_only)
+ dhd_os_sdunlock(dhdp);
#endif /* DHDTHREAD */
return -1;
}
}
if (dhd->pub.busstate != DHD_BUS_LOAD) {
#ifdef DHDTHREAD
- dhd_os_sdunlock(dhdp);
+ if (dhd->threads_only)
+ dhd_os_sdunlock(dhdp);
#endif /* DHDTHREAD */
return -ENETDOWN;
}
@@ -2745,7 +2850,8 @@ dhd_bus_start(dhd_pub_t *dhdp)
DHD_ERROR(("%s, dhd_bus_init failed %d\n", __FUNCTION__, ret));
#ifdef DHDTHREAD
- dhd_os_sdunlock(dhdp);
+ if (dhd->threads_only)
+ dhd_os_sdunlock(dhdp);
#endif /* DHDTHREAD */
return ret;
}
@@ -2761,7 +2867,8 @@ dhd_bus_start(dhd_pub_t *dhdp)
DHD_ERROR(("%s Host failed to register for OOB\n", __FUNCTION__));
#ifdef DHDTHREAD
- dhd_os_sdunlock(dhdp);
+ if (dhd->threads_only)
+ dhd_os_sdunlock(dhdp);
#endif /* DHDTHREAD */
return -ENODEV;
}
@@ -2778,13 +2885,15 @@ dhd_bus_start(dhd_pub_t *dhdp)
del_timer_sync(&dhd->timer);
DHD_ERROR(("%s failed bus is not ready\n", __FUNCTION__));
#ifdef DHDTHREAD
- dhd_os_sdunlock(dhdp);
+ if (dhd->threads_only)
+ dhd_os_sdunlock(dhdp);
#endif /* DHDTHREAD */
return -ENODEV;
}
#ifdef DHDTHREAD
- dhd_os_sdunlock(dhdp);
+ if (dhd->threads_only)
+ dhd_os_sdunlock(dhdp);
#endif /* DHDTHREAD */
#ifdef READ_MACADDR
@@ -2799,45 +2908,89 @@ dhd_bus_start(dhd_pub_t *dhdp)
dhd_write_macaddr(dhd->pub.mac.octet);
#endif
+#ifdef ARP_OFFLOAD_SUPPORT
+ if (dhd->pend_ipaddr) {
+#ifdef AOE_IP_ALIAS_SUPPORT
+ aoe_update_host_ipv4_table(&dhd->pub, dhd->pend_ipaddr, TRUE);
+#endif /* AOE_IP_ALIAS_SUPPORT */
+ dhd->pend_ipaddr = 0;
+ }
+#endif /* ARP_OFFLOAD_SUPPORT */
+
return 0;
}
+#if !defined(AP) && defined(WLP2P) && defined(WL_ENABLE_P2P_IF)
+/* For Android ICS MR2 release, the concurrent mode is enabled by default and the firmware
+ * name would be fw_bcmdhd.bin. So we need to determine whether P2P is enabled in the STA
+ * firmware and accordingly enable concurrent mode (Apply P2P settings). SoftAP firmware
+ * would still be named as fw_bcmdhd_apsta.
+ */
+static u32
+dhd_concurrent_fw(dhd_pub_t *dhd)
+{
+ int ret = 0;
+ char buf[WLC_IOCTL_SMLEN];
+
+ if ((!op_mode) && (strstr(fw_path, "_p2p") == NULL) &&
+ (strstr(fw_path, "_apsta") == NULL)) {
+ /* Given path is for the STA firmware. Check whether P2P support is present in
+ * the firmware. If so, set mode as P2P (concurrent support).
+ */
+ memset(buf, 0, sizeof(buf));
+ bcm_mkiovar("p2p", 0, 0, buf, sizeof(buf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf),
+ FALSE, 0)) < 0) {
+ DHD_TRACE(("%s: Get P2P failed (error=%d)\n", __FUNCTION__, ret));
+ } else if (buf[0] == 1) {
+ DHD_TRACE(("%s: P2P is supported\n", __FUNCTION__));
+ return 1;
+ }
+ }
+ return 0;
+}
+#endif
+
int
dhd_preinit_ioctls(dhd_pub_t *dhd)
{
int ret = 0;
char eventmask[WL_EVENTING_MASK_LEN];
char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */
-
+#if !defined(WL_CFG80211)
uint up = 0;
+#endif
uint power_mode = PM_FAST;
uint32 dongle_align = DHD_SDALIGN;
uint32 glom = 0;
- uint bcn_timeout = 4;
+ uint bcn_timeout = DHD_BEACON_TIMEOUT_NORMAL;
+
uint retry_max = 3;
#if defined(ARP_OFFLOAD_SUPPORT)
int arpoe = 1;
#endif
- int scan_assoc_time = 40;
+#if defined(KEEP_ALIVE)
+ int res;
+#endif /* defined(KEEP_ALIVE) */
+ int scan_assoc_time = DHD_SCAN_ACTIVE_TIME;
int scan_unassoc_time = 40;
- int scan_passive_time = 130;
+ int scan_passive_time = DHD_SCAN_PASSIVE_TIME;
char buf[WLC_IOCTL_SMLEN];
char *ptr;
uint32 listen_interval = LISTEN_INTERVAL; /* Default Listen Interval in Beacons */
+ uint16 chipID;
#if defined(SOFTAP)
uint dtim = 1;
#endif
#if (defined(AP) && !defined(WLP2P)) || (!defined(AP) && defined(WL_CFG80211))
uint32 mpc = 0; /* Turn MPC off for AP/APSTA mode */
#endif
-
#if defined(AP) || defined(WLP2P)
uint32 apsta = 1; /* Enable APSTA mode */
#endif /* defined(AP) || defined(WLP2P) */
#ifdef GET_CUSTOM_MAC_ENABLE
struct ether_addr ea_addr;
#endif /* GET_CUSTOM_MAC_ENABLE */
-
DHD_TRACE(("Enter %s\n", __FUNCTION__));
dhd->op_mode = 0;
#ifdef GET_CUSTOM_MAC_ENABLE
@@ -2847,9 +3000,10 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
bcm_mkiovar("cur_etheraddr", (void *)&ea_addr, ETHER_ADDR_LEN, buf, sizeof(buf));
ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
if (ret < 0) {
- DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret));
+ DHD_ERROR(("%s: can't set custom MAC address , error=%d\n", __FUNCTION__, ret));
return BCME_NOTUP;
}
+ memcpy(dhd->mac.octet, ea_addr.octet, ETHER_ADDR_LEN);
} else {
#endif /* GET_CUSTOM_MAC_ENABLE */
/* Get the default device MAC address directly from firmware */
@@ -2867,7 +3021,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
#endif /* GET_CUSTOM_MAC_ENABLE */
#ifdef SET_RANDOM_MAC_SOFTAP
- if (strstr(fw_path, "_apsta") != NULL) {
+ if ((!op_mode && strstr(fw_path, "_apsta") != NULL) || (op_mode == HOSTAPD_MASK)) {
uint rand_mac;
srandom32((uint)jiffies);
@@ -2889,26 +3043,53 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
#endif /* SET_RANDOM_MAC_SOFTAP */
DHD_TRACE(("Firmware = %s\n", fw_path));
-#if !defined(AP) && defined(WLP2P)
+#if !defined(AP) && defined(WLP2P)
/* Check if firmware with WFD support used */
- if (strstr(fw_path, "_p2p") != NULL) {
+ if ((!op_mode && strstr(fw_path, "_p2p") != NULL)
+#if defined(WL_ENABLE_P2P_IF)
+ || (op_mode == 0x04) ||(dhd_concurrent_fw(dhd))
+#endif
+ ) {
bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf));
if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
DHD_ERROR(("%s APSTA for WFD failed ret= %d\n", __FUNCTION__, ret));
} else {
dhd->op_mode |= WFD_MASK;
-#if defined(ARP_OFFLOAD_SUPPORT)
- arpoe = 0;
-#endif /* (ARP_OFFLOAD_SUPPORT) */
- dhd_pkt_filter_enable = FALSE;
}
}
#endif
#if !defined(AP) && defined(WL_CFG80211)
/* Check if firmware with HostAPD support used */
- if (strstr(fw_path, "_apsta") != NULL) {
+ if ((!op_mode && strstr(fw_path, "_apsta") != NULL) || (op_mode == HOSTAPD_MASK)) {
+ /* Disable A-band for HostAPD */
+ uint band = WLC_BAND_2G;
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_BAND, (char *)&band, sizeof(band),
+ TRUE, 0)) < 0) {
+ DHD_ERROR(("%s:set band failed error (%d)\n", __FUNCTION__, ret));
+ }
+
+ /* Turn off wme if we are having only g ONLY firmware */
+ bcm_mkiovar("nmode", 0, 0, buf, sizeof(buf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf),
+ FALSE, 0)) < 0) {
+ DHD_ERROR(("%s:get nmode failed error (%d)\n", __FUNCTION__, ret));
+ }
+ else {
+ DHD_TRACE(("%s:get nmode returned %d\n", __FUNCTION__,buf[0]));
+ }
+ if (buf[0] == 0) {
+ int wme = 0;
+ bcm_mkiovar("wme", (char *)&wme, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s set wme for HostAPD failed %d\n", __FUNCTION__, ret));
+ }
+ else {
+ DHD_TRACE(("%s set wme succeeded for g ONLY firmware\n", __FUNCTION__));
+ }
+ }
/* Turn off MPC in AP mode */
bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf));
if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
@@ -2957,9 +3138,13 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, sizeof(iovbuf));
dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
- /* disable glom option per default */
- bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ /* disable glom option for some chips */
+ chipID = (uint16)dhd_bus_chip_id(dhd);
+ if ((chipID == BCM4330_CHIP_ID) || (chipID == BCM4329_CHIP_ID)) {
+ DHD_INFO(("%s disable glom for chipID=0x%X\n", __FUNCTION__, chipID));
+ bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ }
/* Setup timeout if Beacons are lost and roam is off to report link down */
bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf));
@@ -2967,6 +3152,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
/* Setup assoc_retry_max count to reconnect target AP in dongle */
bcm_mkiovar("assoc_retry_max", (char *)&retry_max, 4, iovbuf, sizeof(iovbuf));
dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+
#if defined(AP) && !defined(WLP2P)
/* Turn off MPC in AP mode */
bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf));
@@ -2982,17 +3168,13 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
#endif
#if defined(KEEP_ALIVE)
- {
/* Set Keep Alive : be sure to use FW with -keepalive */
- int res;
-
#if defined(SOFTAP)
if (ap_fw_loaded == FALSE)
#endif
if ((res = dhd_keep_alive_onoff(dhd)) < 0)
DHD_ERROR(("%s set keeplive failed %d\n",
__FUNCTION__, res));
- }
#endif /* defined(KEEP_ALIVE) */
/* Read event_msgs mask */
@@ -3019,6 +3201,8 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
setbit(eventmask, WLC_E_LINK);
setbit(eventmask, WLC_E_NDIS_LINK);
setbit(eventmask, WLC_E_MIC_ERROR);
+ setbit(eventmask, WLC_E_ASSOC_REQ_IE);
+ setbit(eventmask, WLC_E_ASSOC_RESP_IE);
setbit(eventmask, WLC_E_PMKID_CACHE);
setbit(eventmask, WLC_E_JOIN_START);
setbit(eventmask, WLC_E_SCAN_COMPLETE);
@@ -3072,12 +3256,13 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
#ifdef PKT_FILTER_SUPPORT
/* Setup defintions for pktfilter , enable in suspend */
- dhd->pktfilter_count = 4;
+ dhd->pktfilter_count = 5;
/* Setup filter to allow only unicast */
dhd->pktfilter[0] = "100 0 0 0 0x01 0x00";
dhd->pktfilter[1] = NULL;
dhd->pktfilter[2] = NULL;
dhd->pktfilter[3] = NULL;
+ dhd->pktfilter[4] = "104 0 0 0 0xFFFFFFFFFFFF 0x01005E0000FB";
#if defined(SOFTAP)
if (ap_fw_loaded) {
int i;
@@ -3089,12 +3274,13 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
#endif /* defined(SOFTAP) */
#endif /* PKT_FILTER_SUPPORT */
+#if !defined(WL_CFG80211)
/* Force STA UP */
if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_UP, (char *)&up, sizeof(up), TRUE, 0)) < 0) {
DHD_ERROR(("%s Setting WL UP failed %d\n", __FUNCTION__, ret));
goto done;
}
-
+#endif
/* query for 'ver' to get version info from firmware */
memset(buf, 0, sizeof(buf));
ptr = buf;
@@ -3105,8 +3291,15 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
bcmstrtok(&ptr, "\n", 0);
/* Print fw version info */
DHD_ERROR(("Firmware version = %s\n", buf));
+
DHD_BLOG(buf, strlen(buf) + 1);
DHD_BLOG(dhd_version, strlen(dhd_version) + 1);
+
+ /* Check and adjust IOCTL response timeout for Manufactring firmware */
+ if (strstr(buf, MANUFACTRING_FW) != NULL) {
+ dhd_os_set_ioctl_resp_timeout(IOCTL_RESP_TIMEOUT * 10);
+ DHD_ERROR(("%s : adjust IOCTL response time for Manufactring Firmware\n", __FUNCTION__));
+ }
}
done:
@@ -3138,26 +3331,6 @@ dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, uint cmd_len, in
return ret;
}
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
-static struct net_device_ops dhd_ops_pri = {
- .ndo_open = dhd_open,
- .ndo_stop = dhd_stop,
- .ndo_get_stats = dhd_get_stats,
- .ndo_do_ioctl = dhd_ioctl_entry,
- .ndo_start_xmit = dhd_start_xmit,
- .ndo_set_mac_address = dhd_set_mac_address,
- .ndo_set_multicast_list = dhd_set_multicast_list,
-};
-
-static struct net_device_ops dhd_ops_virt = {
- .ndo_get_stats = dhd_get_stats,
- .ndo_do_ioctl = dhd_ioctl_entry,
- .ndo_start_xmit = dhd_start_xmit,
- .ndo_set_mac_address = dhd_set_mac_address,
- .ndo_set_multicast_list = dhd_set_multicast_list,
-};
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) */
-
int dhd_change_mtu(dhd_pub_t *dhdp, int new_mtu, int ifidx)
{
struct dhd_info *dhd = dhdp->info;
@@ -3261,9 +3434,13 @@ static int dhd_device_event(struct notifier_block *this,
DHD_ARPOE(("%s: [%s] Up IP: 0x%x\n",
__FUNCTION__, ifa->ifa_label, ifa->ifa_address));
- /* firmware not downloaded, do nothing */
- if (dhd->pub.busstate == DHD_BUS_DOWN) {
- DHD_ERROR(("%s: bus is down, exit\n", __FUNCTION__));
+ if (dhd->pub.busstate != DHD_BUS_DATA) {
+ DHD_ERROR(("%s: bus not ready, exit\n", __FUNCTION__));
+ if (dhd->pend_ipaddr) {
+ DHD_ERROR(("%s: overwrite pending ipaddr: 0x%x\n",
+ __FUNCTION__, dhd->pend_ipaddr));
+ }
+ dhd->pend_ipaddr = ifa->ifa_address;
break;
}
@@ -3281,7 +3458,7 @@ static int dhd_device_event(struct notifier_block *this,
case NETDEV_DOWN:
DHD_ARPOE(("%s: [%s] Down IP: 0x%x\n",
__FUNCTION__, ifa->ifa_label, ifa->ifa_address));
-
+ dhd->pend_ipaddr = 0;
#ifdef AOE_IP_ALIAS_SUPPORT
if (!(ifa->ifa_label[strlen(ifa->ifa_label)-2] == 0x3a)) {
DHD_ARPOE(("%s: primary interface is down, AOE clr all\n",
@@ -3355,7 +3532,8 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx)
* portable hotspot. This will not work in simultaneous AP/STA mode,
* nor with P2P. Need to set the Donlge's MAC address, and then use that.
*/
- if (ifidx > 0) {
+ if (!memcmp(temp_addr, dhd->iflist[0]->mac_addr,
+ ETHER_ADDR_LEN)) {
DHD_ERROR(("%s interface [%s]: set locally administered bit in MAC\n",
__func__, net->name));
temp_addr[0] |= 0x02;
@@ -3468,13 +3646,17 @@ void dhd_detach(dhd_pub_t *dhdp)
unregister_inetaddr_notifier(&dhd_notifier);
#endif /* ARP_OFFLOAD_SUPPORT */
-#if defined(CONFIG_HAS_EARLYSUSPEND)
+#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
if (dhd->dhd_state & DHD_ATTACH_STATE_EARLYSUSPEND_DONE) {
if (dhd->early_suspend.suspend)
unregister_early_suspend(&dhd->early_suspend);
}
#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+ cancel_work_sync(&dhd->work_hang);
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
+
#if defined(CONFIG_BCMDHD_WEXT)
if (dhd->dhd_state & DHD_ATTACH_STATE_WL_ATTACH) {
/* Detatch and unlink in the iw */
@@ -3482,7 +3664,7 @@ void dhd_detach(dhd_pub_t *dhdp)
}
#endif /* defined(CONFIG_BCMDHD_WEXT) */
- if (&dhd->thr_sysioc_ctl.thr_pid >= 0) {
+ if (dhd->thr_sysioc_ctl.thr_pid >= 0) {
PROC_STOP(&dhd->thr_sysioc_ctl);
}
@@ -3492,13 +3674,15 @@ void dhd_detach(dhd_pub_t *dhdp)
dhd_if_t *ifp;
/* Cleanup virtual interfaces */
- for (i = 1; i < DHD_MAX_IFS; i++)
+ for (i = 1; i < DHD_MAX_IFS; i++) {
+ dhd_net_if_lock_local(dhd);
if (dhd->iflist[i]) {
dhd->iflist[i]->state = DHD_IF_DEL;
dhd->iflist[i]->idx = i;
dhd_op_if(dhd->iflist[i]);
}
-
+ dhd_net_if_unlock_local(dhd);
+ }
/* delete primary interface 0 */
ifp = dhd->iflist[0];
ASSERT(ifp);
@@ -3549,7 +3733,7 @@ void dhd_detach(dhd_pub_t *dhdp)
#ifdef WL_CFG80211
if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) {
- wl_cfg80211_detach();
+ wl_cfg80211_detach(NULL);
dhd_monitor_uninit();
}
#endif
@@ -3562,6 +3746,7 @@ void dhd_detach(dhd_pub_t *dhdp)
#ifdef CONFIG_HAS_WAKELOCK
wake_lock_destroy(&dhd->wl_wifi);
wake_lock_destroy(&dhd->wl_rxwake);
+ wake_lock_destroy(&dhd->wl_ctrlwake);
#endif
}
}
@@ -3596,7 +3781,6 @@ dhd_module_cleanup(void)
dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF);
}
-
static int __init
dhd_module_init(void)
{
@@ -3643,26 +3827,26 @@ dhd_module_init(void)
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
- /*
- * Wait till MMC sdio_register_driver callback called and made driver attach.
- * It's needed to make sync up exit from dhd insmod and
- * Kernel MMC sdio device callback registration
- */
+ /*
+ * Wait till MMC sdio_register_driver callback called and made driver attach.
+ * It's needed to make sync up exit from dhd insmod and
+ * Kernel MMC sdio device callback registration
+ */
if (down_timeout(&dhd_registration_sem, msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT)) != 0) {
- error = -EINVAL;
+ error = -ENODEV;
DHD_ERROR(("%s: sdio_register_driver timeout\n", __FUNCTION__));
goto fail_2;
- }
+ }
#endif
#if defined(WL_CFG80211)
- error = wl_android_post_init();
-#endif
+ wl_android_post_init();
+#endif /* defined(WL_CFG80211) */
return error;
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && 1
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
fail_2:
dhd_bus_unregister();
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
+#endif
fail_1:
#if defined(CONFIG_WIFI_CONTROL_FUNC)
wl_android_wifictrl_func_del();
@@ -3674,7 +3858,11 @@ fail_1:
return error;
}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
late_initcall(dhd_module_init);
+#else
+module_init(dhd_module_init);
+#endif
module_exit(dhd_module_cleanup);
/*
@@ -3722,7 +3910,6 @@ int
dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition, bool *pending)
{
dhd_info_t * dhd = (dhd_info_t *)(pub->info);
- DECLARE_WAITQUEUE(wait, current);
int timeout = dhd_ioctl_timeout_msec;
/* Convert timeout in millsecond to jiffies */
@@ -3732,26 +3919,7 @@ dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition, bool *pending)
timeout = timeout * HZ / 1000;
#endif
- /* Wait until control frame is available */
- add_wait_queue(&dhd->ioctl_resp_wait, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
-
- /* Memory barrier to support multi-processing
- * As the variable "condition", which points to dhd->rxlen (dhd_bus_rxctl[dhd_sdio.c])
- * Can be changed by another processor.
- */
- smp_mb();
- while (!(*condition) && (!signal_pending(current) && timeout)) {
- timeout = schedule_timeout(timeout);
- smp_mb();
- }
-
- if (signal_pending(current))
- *pending = TRUE;
-
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&dhd->ioctl_resp_wait, &wait);
-
+ timeout = wait_event_timeout(dhd->ioctl_resp_wait, (*condition), timeout);
return timeout;
}
@@ -3761,7 +3929,7 @@ dhd_os_ioctl_resp_wake(dhd_pub_t *pub)
dhd_info_t *dhd = (dhd_info_t *)(pub->info);
if (waitqueue_active(&dhd->ioctl_resp_wait)) {
- wake_up_interruptible(&dhd->ioctl_resp_wait);
+ wake_up(&dhd->ioctl_resp_wait);
}
return 0;
@@ -3917,7 +4085,7 @@ dhd_os_sdtxunlock(dhd_pub_t *pub)
dhd_os_sdunlock(pub);
}
-#if defined(DHD_USE_STATIC_BUF)
+#if defined(CONFIG_DHD_USE_STATIC_BUF)
uint8* dhd_os_prealloc(void *osh, int section, uint size)
{
return (uint8*)wl_android_prealloc(section, size);
@@ -3926,7 +4094,7 @@ uint8* dhd_os_prealloc(void *osh, int section, uint size)
void dhd_os_prefree(void *osh, void *addr, uint size)
{
}
-#endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */
+#endif /* defined(CONFIG_DHD_USE_STATIC_BUF) */
#if defined(CONFIG_BCMDHD_WEXT)
struct iw_statistics *
@@ -3975,7 +4143,13 @@ dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata,
#endif /* defined(CONFIG_BCMDHD_WEXT) */
#ifdef WL_CFG80211
-
+ if ((ntoh32(event->event_type) == WLC_E_IF) &&
+ (((dhd_if_event_t *)*data)->action == WLC_E_IF_ADD))
+ /* If ADD_IF has been called directly by wl utility then we
+ * should not report this. In case if ADD_IF was called from
+ * CFG stack, then too this event need not be reported back
+ */
+ return (BCME_OK);
if ((wl_cfg80211_is_progress_ifchange() ||
wl_cfg80211_is_progress_ifadd()) && (*ifidx != 0)) {
/*
@@ -4104,8 +4278,13 @@ void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar)
{
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
struct dhd_info *dhdinfo = dhd->info;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+ int timeout = msecs_to_jiffies(2000);
+#else
+ int timeout = 2 * HZ;
+#endif
dhd_os_sdunlock(dhd);
- wait_event_interruptible_timeout(dhdinfo->ctrl_wait, (*lockvar == FALSE), HZ * 2);
+ wait_event_timeout(dhdinfo->ctrl_wait, (*lockvar == FALSE), timeout);
dhd_os_sdlock(dhd);
#endif
return;
@@ -4116,7 +4295,7 @@ void dhd_wait_event_wakeup(dhd_pub_t *dhd)
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
struct dhd_info *dhdinfo = dhd->info;
if (waitqueue_active(&dhdinfo->ctrl_wait))
- wake_up_interruptible(&dhdinfo->ctrl_wait);
+ wake_up(&dhdinfo->ctrl_wait);
#endif
return;
}
@@ -4149,16 +4328,18 @@ int net_os_set_suspend_disable(struct net_device *dev, int val)
return ret;
}
-int net_os_set_suspend(struct net_device *dev, int val)
+int net_os_set_suspend(struct net_device *dev, int val, int force)
{
int ret = 0;
-#if defined(CONFIG_HAS_EARLYSUSPEND)
dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
if (dhd) {
+#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
ret = dhd_set_suspend(val, &dhd->pub);
+#else
+ ret = dhd_suspend_resume_helper(dhd, val, force);
+#endif
}
-#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */
return ret;
}
@@ -4178,7 +4359,8 @@ int net_os_rxfilter_add_remove(struct net_device *dev, int add_remove, int num)
char *filterp = NULL;
int ret = 0;
- if (!dhd || (num == DHD_UNICAST_FILTER_NUM))
+ if (!dhd || (num == DHD_UNICAST_FILTER_NUM) ||
+ (num == DHD_MDNS_FILTER_NUM))
return ret;
if (num >= dhd->pub.pktfilter_count)
return -EINVAL;
@@ -4201,9 +4383,8 @@ int net_os_rxfilter_add_remove(struct net_device *dev, int add_remove, int num)
return ret;
}
-int net_os_set_packet_filter(struct net_device *dev, int val)
+int dhd_os_set_packet_filter(dhd_pub_t *dhdp, int val)
{
- dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
int ret = 0;
/* Packet filtering is set only if we still in early-suspend and
@@ -4211,22 +4392,29 @@ int net_os_set_packet_filter(struct net_device *dev, int val)
* We can always turn it OFF in case of early-suspend, but we turn it
* back ON only if suspend_disable_flag was not set
*/
- if (dhd && dhd->pub.up) {
- if (dhd->pub.in_suspend) {
- if (!val || (val && !dhd->pub.suspend_disable_flag))
- dhd_set_packet_filter(val, &dhd->pub);
+ if (dhdp && dhdp->up) {
+ if (dhdp->in_suspend) {
+ if (!val || (val && !dhdp->suspend_disable_flag))
+ dhd_set_packet_filter(val, dhdp);
}
}
return ret;
+
}
+int net_os_set_packet_filter(struct net_device *dev, int val)
+{
+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
-void
+ return dhd_os_set_packet_filter(&dhd->pub, val);
+}
+
+int
dhd_dev_init_ioctl(struct net_device *dev)
{
dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
- dhd_preinit_ioctls(&dhd->pub);
+ return dhd_preinit_ioctls(&dhd->pub);
}
#ifdef PNO_SUPPORT
@@ -4271,6 +4459,28 @@ dhd_dev_get_pno_status(struct net_device *dev)
#endif /* PNO_SUPPORT */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+static void dhd_hang_process(struct work_struct *work)
+{
+ dhd_info_t *dhd;
+ struct net_device *dev;
+
+ dhd = (dhd_info_t *)container_of(work, dhd_info_t, work_hang);
+ dev = dhd->iflist[0]->net;
+
+ if (dev) {
+ rtnl_lock();
+ dev_close(dev);
+ rtnl_unlock();
+#if defined(WL_WIRELESS_EXT)
+ wl_iw_send_priv_event(dev, "HANG");
+#endif
+#if defined(WL_CFG80211)
+ wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED);
+#endif
+ }
+}
+
int net_os_send_hang_message(struct net_device *dev)
{
dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
@@ -4279,26 +4489,21 @@ int net_os_send_hang_message(struct net_device *dev)
if (dhd) {
if (!dhd->pub.hang_was_sent) {
dhd->pub.hang_was_sent = 1;
-#if defined(CONFIG_BCMDHD_WEXT)
- ret = wl_iw_send_priv_event(dev, "HANG");
-#endif
-#if defined(WL_CFG80211)
- ret = wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED);
-#endif
+ schedule_work(&dhd->work_hang);
}
}
return ret;
}
+#endif
void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec)
{
dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
if (dhd && dhd->pub.up)
- memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t));
+ memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t));
}
-
void dhd_net_if_lock(struct net_device *dev)
{
dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
@@ -4327,6 +4532,24 @@ static void dhd_net_if_unlock_local(dhd_info_t *dhd)
#endif
}
+static void dhd_suspend_lock(dhd_pub_t *pub)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
+ dhd_info_t *dhd = (dhd_info_t *)(pub->info);
+ if (dhd)
+ mutex_lock(&dhd->dhd_suspend_mutex);
+#endif
+}
+
+static void dhd_suspend_unlock(dhd_pub_t *pub)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
+ dhd_info_t *dhd = (dhd_info_t *)(pub->info);
+ if (dhd)
+ mutex_unlock(&dhd->dhd_suspend_mutex);
+#endif
+}
+
unsigned long dhd_os_spin_lock(dhd_pub_t *pub)
{
dhd_info_t *dhd = (dhd_info_t *)(pub->info);
@@ -4419,13 +4642,18 @@ int dhd_os_wake_lock_timeout(dhd_pub_t *pub)
if (dhd) {
spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
- ret = dhd->wakelock_timeout_enable;
+ ret = dhd->wakelock_rx_timeout_enable > dhd->wakelock_ctrl_timeout_enable ?
+ dhd->wakelock_rx_timeout_enable : dhd->wakelock_ctrl_timeout_enable;
#ifdef CONFIG_HAS_WAKELOCK
- if (dhd->wakelock_timeout_enable)
+ if (dhd->wakelock_rx_timeout_enable)
wake_lock_timeout(&dhd->wl_rxwake,
- dhd->wakelock_timeout_enable * HZ);
+ msecs_to_jiffies(dhd->wakelock_rx_timeout_enable));
+ if (dhd->wakelock_ctrl_timeout_enable)
+ wake_lock_timeout(&dhd->wl_ctrlwake,
+ msecs_to_jiffies(dhd->wakelock_ctrl_timeout_enable));
#endif
- dhd->wakelock_timeout_enable = 0;
+ dhd->wakelock_rx_timeout_enable = 0;
+ dhd->wakelock_ctrl_timeout_enable = 0;
spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
}
return ret;
@@ -4441,27 +4669,51 @@ int net_os_wake_lock_timeout(struct net_device *dev)
return ret;
}
-int dhd_os_wake_lock_timeout_enable(dhd_pub_t *pub, int val)
+int dhd_os_wake_lock_rx_timeout_enable(dhd_pub_t *pub, int val)
{
dhd_info_t *dhd = (dhd_info_t *)(pub->info);
unsigned long flags;
if (dhd) {
spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
- if (val > dhd->wakelock_timeout_enable)
- dhd->wakelock_timeout_enable = val;
+ if (val > dhd->wakelock_rx_timeout_enable)
+ dhd->wakelock_rx_timeout_enable = val;
spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
}
return 0;
}
-int net_os_wake_lock_timeout_enable(struct net_device *dev, int val)
+int dhd_os_wake_lock_ctrl_timeout_enable(dhd_pub_t *pub, int val)
+{
+ dhd_info_t *dhd = (dhd_info_t *)(pub->info);
+ unsigned long flags;
+
+ if (dhd) {
+ spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
+ if (val > dhd->wakelock_ctrl_timeout_enable)
+ dhd->wakelock_ctrl_timeout_enable = val;
+ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
+ }
+ return 0;
+}
+
+int net_os_wake_lock_rx_timeout_enable(struct net_device *dev, int val)
{
dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
int ret = 0;
if (dhd)
- ret = dhd_os_wake_lock_timeout_enable(&dhd->pub, val);
+ ret = dhd_os_wake_lock_rx_timeout_enable(&dhd->pub, val);
+ return ret;
+}
+
+int net_os_wake_lock_ctrl_timeout_enable(struct net_device *dev, int val)
+{
+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
+ int ret = 0;
+
+ if (dhd)
+ ret = dhd_os_wake_lock_ctrl_timeout_enable(&dhd->pub, val);
return ret;
}
@@ -4532,15 +4784,6 @@ int dhd_os_check_wakelock(void *dhdp)
return 0;
}
-int dhd_os_check_if_up(void *dhdp)
-{
- dhd_pub_t *pub = (dhd_pub_t *)dhdp;
-
- if (!pub)
- return 0;
- return pub->up;
-}
-
int net_os_wake_unlock(struct net_device *dev)
{
dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
@@ -4551,6 +4794,15 @@ int net_os_wake_unlock(struct net_device *dev)
return ret;
}
+int dhd_os_check_if_up(void *dhdp)
+{
+ dhd_pub_t *pub = (dhd_pub_t *)dhdp;
+
+ if (!pub)
+ return 0;
+ return pub->up;
+}
+
int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd)
{
int ifidx;
@@ -4590,8 +4842,8 @@ extern int dhd_wlfc_interface_entry_update(void* state, ewlfc_mac_entry_action_t
uint8 iftype, uint8* ea);
extern int dhd_wlfc_FIFOcreditmap_update(void* state, uint8* credits);
-int dhd_wlfc_interface_event(struct dhd_info *dhd, uint8 action, uint8 ifid, uint8 iftype,
- uint8* ea)
+int dhd_wlfc_interface_event(struct dhd_info *dhd,
+ ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea)
{
if (dhd->pub.wlfc_state == NULL)
return BCME_OK;
diff --git a/drivers/net/wireless/bcmdhd/dhd_linux_mon.c b/drivers/net/wireless/bcmdhd/dhd_linux_mon.c
index dd9c71f75be6..d4dca2607212 100644
--- a/drivers/net/wireless/bcmdhd/dhd_linux_mon.c
+++ b/drivers/net/wireless/bcmdhd/dhd_linux_mon.c
@@ -2,13 +2,13 @@
* Broadcom Dongle Host Driver (DHD), Linux monitor network interface
*
* Copyright (C) 1999-2011, Broadcom Corporation
- *
+ *
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
- *
+ *
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
@@ -16,12 +16,12 @@
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
- *
+ *
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: dhd_linux_mon.c,v 1.131.2.55 2011-02-09 05:31:56 Exp $
+ * $Id: dhd_linux_mon.c 297563 2011-11-20 15:38:29Z $
*/
#include <linux/string.h>
@@ -96,16 +96,30 @@ static const struct net_device_ops dhd_mon_if_ops = {
static struct net_device* lookup_real_netdev(char *name)
{
int i;
+ int len = 0;
int last_name_len = 0;
struct net_device *ndev;
struct net_device *ndev_found = NULL;
- /* We want to find interface "p2p-eth0-0" for monitor interface "mon.p2p-eth0-0", so
- * we skip "eth0" even if "mon.p2p-eth0-0" contains "eth0"
+ /* We need to find interface "p2p-p2p-0" corresponding to monitor interface "mon-p2p-0",
+ * Once mon iface name reaches IFNAMSIZ, it is reset to p2p0-0 and corresponding mon
+ * iface would be mon-p2p0-0.
*/
for (i = 0; i < DHD_MAX_IFS; i++) {
ndev = dhd_idx2net(g_monitor.dhd_pub, i);
- if (ndev && strstr(name, ndev->name)) {
+
+ /* Skip "p2p" and look for "-p2p0-x" in monitor interface name. If it
+ * it matches, then this netdev is the corresponding real_netdev.
+ */
+ if (ndev && strstr(ndev->name, "p2p-p2p0")) {
+ len = strlen("p2p");
+ } else {
+ /* if p2p- is not present, then the IFNAMSIZ have reached and name
+ * would have got reset. In this casse,look for p2p0-x in mon-p2p0-x
+ */
+ len = 0;
+ }
+ if (ndev && strstr(name, (ndev->name + len))) {
if (strlen(ndev->name) > last_name_len) {
ndev_found = ndev;
last_name_len = strlen(ndev->name);
@@ -225,9 +239,10 @@ static void dhd_mon_if_set_multicast_list(struct net_device *ndev)
mon_if = ndev_to_monif(ndev);
if (mon_if == NULL || mon_if->real_ndev == NULL) {
MON_PRINT(" cannot find matched net dev, skip the packet\n");
+ } else {
+ MON_PRINT("enter, if name: %s, matched if name %s\n",
+ ndev->name, mon_if->real_ndev->name);
}
-
- MON_PRINT("enter, if name: %s, matched if name %s\n", ndev->name, mon_if->real_ndev->name);
}
static int dhd_mon_if_change_mac(struct net_device *ndev, void *addr)
@@ -238,9 +253,10 @@ static int dhd_mon_if_change_mac(struct net_device *ndev, void *addr)
mon_if = ndev_to_monif(ndev);
if (mon_if == NULL || mon_if->real_ndev == NULL) {
MON_PRINT(" cannot find matched net dev, skip the packet\n");
+ } else {
+ MON_PRINT("enter, if name: %s, matched if name %s\n",
+ ndev->name, mon_if->real_ndev->name);
}
-
- MON_PRINT("enter, if name: %s, matched if name %s\n", ndev->name, mon_if->real_ndev->name);
return ret;
}
diff --git a/drivers/net/wireless/bcmdhd/dhd_proto.h b/drivers/net/wireless/bcmdhd/dhd_proto.h
index e0a54ad02692..bb1d7365ea94 100644
--- a/drivers/net/wireless/bcmdhd/dhd_proto.h
+++ b/drivers/net/wireless/bcmdhd/dhd_proto.h
@@ -34,7 +34,7 @@
#include <wlioctl.h>
#ifndef IOCTL_RESP_TIMEOUT
-#define IOCTL_RESP_TIMEOUT 20000 /* In milli second */
+#define IOCTL_RESP_TIMEOUT 2000 /* In milli second */
#endif
/*
diff --git a/drivers/net/wireless/bcmdhd/dhd_sdio.c b/drivers/net/wireless/bcmdhd/dhd_sdio.c
index 57aee5705454..2cac95f2def4 100644
--- a/drivers/net/wireless/bcmdhd/dhd_sdio.c
+++ b/drivers/net/wireless/bcmdhd/dhd_sdio.c
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: dhd_sdio.c 288105 2011-10-06 01:58:02Z $
+ * $Id: dhd_sdio.c 326662 2012-04-10 06:38:08Z $
*/
#include <typedefs.h>
@@ -382,7 +382,7 @@ static bool dhd_readahead;
/* To check if there's window offered */
#define DATAOK(bus) \
- (((uint8)(bus->tx_max - bus->tx_seq) > 2) && \
+ (((uint8)(bus->tx_max - bus->tx_seq) > 1) && \
(((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
/* To check if there's window offered for ctrl frame */
@@ -801,7 +801,8 @@ dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok)
#ifdef DHD_DEBUG
if (dhd_console_ms == 0)
#endif /* DHD_DEBUG */
- dhd_os_wd_timer(bus->dhd, 0);
+ if (bus->poll == 0)
+ dhd_os_wd_timer(bus->dhd, 0);
break;
}
#ifdef DHD_DEBUG
@@ -851,8 +852,10 @@ dhdsdio_bussleep(dhd_bus_t *bus, bool sleep)
SBSDIO_FORCE_HW_CLKREQ_OFF, NULL);
/* Isolate the bus */
- bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL,
- SBSDIO_DEVCTL_PADS_ISO, NULL);
+ if (bus->sih->chip != BCM4329_CHIP_ID && bus->sih->chip != BCM4319_CHIP_ID) {
+ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL,
+ SBSDIO_DEVCTL_PADS_ISO, NULL);
+ }
/* Change state */
bus->sleeping = TRUE;
@@ -1366,9 +1369,7 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
/* Send from dpc */
bus->ctrl_frame_buf = frame;
bus->ctrl_frame_len = len;
-
dhd_wait_for_event(bus->dhd, &bus->ctrl_frame_stat);
-
if (bus->ctrl_frame_stat == FALSE) {
DHD_INFO(("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__));
ret = 0;
@@ -1453,7 +1454,7 @@ dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen)
{
int timeleft;
uint rxlen = 0;
- bool pending;
+ bool pending = FALSE;
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
@@ -1480,8 +1481,9 @@ dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen)
dhd_os_sdunlock(bus->dhd);
#endif /* DHD_DEBUG */
} else if (pending == TRUE) {
- DHD_CTL(("%s: canceled\n", __FUNCTION__));
- return -ERESTARTSYS;
+ /* signal pending */
+ DHD_ERROR(("%s: signal pending\n", __FUNCTION__));
+ return -EINTR;
} else {
DHD_CTL(("%s: resumed for unknown reason?\n", __FUNCTION__));
#ifdef DHD_DEBUG
@@ -1520,7 +1522,7 @@ enum {
#ifdef DHD_DEBUG
IOV_CHECKDIED,
IOV_SERIALCONS,
-#endif
+#endif /* DHD_DEBUG */
IOV_DOWNLOAD,
IOV_SOCRAM_STATE,
IOV_FORCEEVEN,
@@ -2785,6 +2787,9 @@ dhdsdio_download_state(dhd_bus_t *bus, bool enter)
uint retries;
int bcmerror = 0;
+ if (!bus->sih)
+ return BCME_ERROR;
+
/* To enter download state, disable ARM and reset SOCRAM.
* To exit download state, simply reset ARM (default is RAM boot).
*/
@@ -3058,6 +3063,13 @@ dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex)
bus->rxskip = FALSE;
bus->tx_seq = bus->rx_seq = 0;
+ /* Set to a safe default. It gets updated when we
+ * receive a packet from the fw but when we reset,
+ * we need a safe default to be able to send the
+ * initial mac address.
+ */
+ bus->tx_max = 4;
+
if (enforce_mutex)
dhd_os_sdunlock(bus->dhd);
}
@@ -3112,9 +3124,9 @@ dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex)
dhd_timeout_start(&tmo, DHD_WAIT_F2RDY * 1000);
ready = 0;
- while (ready != enable && !dhd_timeout_expired(&tmo))
- ready = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL);
-
+ do {
+ ready = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL);
+ } while (ready != enable && !dhd_timeout_expired(&tmo));
DHD_INFO(("%s: enable 0x%02x, ready 0x%02x (waited %uus)\n",
__FUNCTION__, enable, ready, tmo.elapsed));
@@ -3565,7 +3577,7 @@ dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq)
if ((uint8)(txmax - bus->tx_seq) > 0x40) {
DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
__FUNCTION__, txmax, bus->tx_seq));
- txmax = bus->tx_seq;
+ txmax = bus->tx_max;
}
bus->tx_max = txmax;
@@ -3766,6 +3778,14 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
!bus->rxskip && rxleft && bus->dhd->busstate != DHD_BUS_DOWN;
rxseq++, rxleft--) {
+#ifdef DHDTHREAD
+ /* tx more to improve rx performance */
+ if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate &&
+ pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) {
+ dhdsdio_sendfromq(bus, dhd_txbound);
+ }
+#endif /* DHDTHREAD */
+
/* Handle glomming separately */
if (bus->glom || bus->glomd) {
uint8 cnt;
@@ -3986,7 +4006,7 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
if ((uint8)(txmax - bus->tx_seq) > 0x40) {
DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
__FUNCTION__, txmax, bus->tx_seq));
- txmax = bus->tx_seq;
+ txmax = bus->tx_max;
}
bus->tx_max = txmax;
@@ -4143,7 +4163,7 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
if ((uint8)(txmax - bus->tx_seq) > 0x40) {
DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
__FUNCTION__, txmax, bus->tx_seq));
- txmax = bus->tx_seq;
+ txmax = bus->tx_max;
}
bus->tx_max = txmax;
@@ -4576,8 +4596,32 @@ clkwait:
bcmsdh_intr_enable(sdh);
}
+#if defined(OOB_INTR_ONLY) && !defined(HW_OOB)
+ /* In case of SW-OOB(using edge trigger),
+ * Check interrupt status in the dongle again after enable irq on the host.
+ * and rechedule dpc if interrupt is pended in the dongle.
+ * There is a chance to miss OOB interrupt while irq is disabled on the host.
+ * No need to do this with HW-OOB(level trigger)
+ */
+ R_SDREG(newstatus, &regs->intstatus, retries);
+ if (bcmsdh_regfail(bus->sdh))
+ newstatus = 0;
+ if (newstatus & bus->hostintmask) {
+ bus->ipend = TRUE;
+ resched = TRUE;
+ }
+#endif /* defined(OOB_INTR_ONLY) && !defined(HW_OOB) */
+
if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) {
int ret, i;
+ uint8* frame_seq = bus->ctrl_frame_buf + SDPCM_FRAMETAG_LEN;
+
+ if (*frame_seq != bus->tx_seq) {
+ DHD_INFO(("%s IOCTL frame seq lag detected!"
+ " frm_seq:%d != bus->tx_seq:%d, corrected\n",
+ __FUNCTION__, *frame_seq, bus->tx_seq));
+ *frame_seq = bus->tx_seq;
+ }
ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
(uint8 *)bus->ctrl_frame_buf, (uint32)bus->ctrl_frame_len,
@@ -5183,16 +5227,17 @@ dhdsdio_chipmatch(uint16 chipid)
return TRUE;
if (chipid == BCM4319_CHIP_ID)
return TRUE;
- if (chipid == BCM4336_CHIP_ID)
- return TRUE;
if (chipid == BCM4330_CHIP_ID)
return TRUE;
+ if (chipid == BCM43239_CHIP_ID)
+ return TRUE;
+ if (chipid == BCM4336_CHIP_ID)
+ return TRUE;
if (chipid == BCM43237_CHIP_ID)
return TRUE;
if (chipid == BCM43362_CHIP_ID)
return TRUE;
- if (chipid == BCM43239_CHIP_ID)
- return TRUE;
+
return FALSE;
}
@@ -5369,6 +5414,7 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
if (ret == BCME_NOTUP)
goto fail;
}
+
/* Ok, have the per-port tell the stack we're open for business */
if (dhd_net_attach(bus->dhd, 0) != 0) {
DHD_ERROR(("%s: Net attach failed!!\n", __FUNCTION__));
@@ -5545,8 +5591,10 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva,
return TRUE;
fail:
- if (bus->sih != NULL)
+ if (bus->sih != NULL) {
si_detach(bus->sih);
+ bus->sih = NULL;
+ }
return FALSE;
}
@@ -5736,7 +5784,7 @@ dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh)
return;
if (bus->rxbuf) {
-#ifndef DHD_USE_STATIC_BUF
+#ifndef CONFIG_DHD_USE_STATIC_BUF
MFREE(osh, bus->rxbuf, bus->rxblen);
#endif
bus->rxctl = bus->rxbuf = NULL;
@@ -5744,7 +5792,7 @@ dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh)
}
if (bus->databuf) {
-#ifndef DHD_USE_STATIC_BUF
+#ifndef CONFIG_DHD_USE_STATIC_BUF
MFREE(osh, bus->databuf, MAX_DATA_BUF);
#endif
bus->databuf = NULL;
@@ -5779,6 +5827,7 @@ dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, bool r
dhdsdio_clkctl(bus, CLK_NONE, FALSE);
}
si_detach(bus->sih);
+ bus->sih = NULL;
if (bus->vars && bus->varsz)
MFREE(osh, bus->vars, bus->varsz);
bus->vars = NULL;
@@ -6155,6 +6204,7 @@ dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf
uint
dhd_bus_chip(struct dhd_bus *bus)
{
+ ASSERT(bus);
ASSERT(bus->sih != NULL);
return bus->sih->chip;
}
@@ -6162,6 +6212,7 @@ dhd_bus_chip(struct dhd_bus *bus)
void *
dhd_bus_pub(struct dhd_bus *bus)
{
+ ASSERT(bus);
return bus->dhd;
}
@@ -6208,7 +6259,6 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
bus->dhd->dongle_reset = TRUE;
bus->dhd->up = FALSE;
dhd_os_sdunlock(dhdp);
-
DHD_TRACE(("%s: WLAN OFF DONE\n", __FUNCTION__));
/* App can now remove power from device */
} else
@@ -6279,6 +6329,14 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
return bcmerror;
}
+/* Get Chip ID version */
+uint dhd_bus_chip_id(dhd_pub_t *dhdp)
+{
+ dhd_bus_t *bus = dhdp->bus;
+
+ return bus->sih->chip;
+}
+
int
dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size)
{
diff --git a/drivers/net/wireless/bcmdhd/dhd_wlfc.h b/drivers/net/wireless/bcmdhd/dhd_wlfc.h
index 59d018b64c6f..c4d251806d78 100644
--- a/drivers/net/wireless/bcmdhd/dhd_wlfc.h
+++ b/drivers/net/wireless/bcmdhd/dhd_wlfc.h
@@ -18,7 +18,7 @@
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
-* $Id: dhd_wlfc.h,v 1.1.8.1 2010-09-09 22:41:08 Exp $
+* $Id: dhd_wlfc.h 286994 2011-09-29 21:27:44Z $
*
*/
#ifndef __wlfc_host_driver_definitions_h__
@@ -201,6 +201,7 @@ typedef struct athost_wl_stat_counters {
#define WLFC_FCMODE_IMPLIED_CREDIT 1
#define WLFC_FCMODE_EXPLICIT_CREDIT 2
+/* How long to defer borrowing in milliseconds */
#define WLFC_BORROW_DEFER_PERIOD_MS 100
/* Mask to represent available ACs (note: BC/MC is ignored */
@@ -261,6 +262,15 @@ typedef struct athost_wl_status_info {
/* Timestamp to compute how long to defer borrowing for */
uint32 borrow_defer_timestamp;
+
} athost_wl_status_info_t;
+int dhd_wlfc_enable(dhd_pub_t *dhd);
+int dhd_wlfc_interface_event(struct dhd_info *,
+ ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea);
+int dhd_wlfc_FIFOcreditmap_event(struct dhd_info *dhd, uint8* event_data);
+int dhd_wlfc_event(struct dhd_info *dhd);
+int dhd_os_wlfc_block(dhd_pub_t *pub);
+int dhd_os_wlfc_unblock(dhd_pub_t *pub);
+
#endif /* __wlfc_host_driver_definitions_h__ */
diff --git a/drivers/net/wireless/bcmdhd/hndpmu.c b/drivers/net/wireless/bcmdhd/hndpmu.c
index b9586e40d0c2..0e493343c806 100644
--- a/drivers/net/wireless/bcmdhd/hndpmu.c
+++ b/drivers/net/wireless/bcmdhd/hndpmu.c
@@ -22,7 +22,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: hndpmu.c,v 1.228.2.56 2011-02-11 22:49:07 Exp $
+ * $Id: hndpmu.c,v 1.228.2.56 2011-02-11 22:49:07 $
*/
#include <typedefs.h>
@@ -93,26 +93,8 @@ static const sdiod_drive_str_t sdiod_drive_strength_tab4_1v8[] = {
{0, 0x1} };
/* SDIO Drive Strength to sel value table for PMU Rev 11 (1.2v) */
-static const sdiod_drive_str_t sdiod_drive_strength_tab4_1v2[] = {
- {16, 0x3},
- {13, 0x2},
- {11, 0x1},
- {8, 0x0},
- {6, 0x7},
- {4, 0x6},
- {2, 0x5},
- {0, 0x4} };
/* SDIO Drive Strength to sel value table for PMU Rev 11 (2.5v) */
-static const sdiod_drive_str_t sdiod_drive_strength_tab4_2v5[] = {
- {80, 0x5},
- {65, 0x4},
- {55, 0x7},
- {40, 0x6},
- {30, 0x1},
- {20, 0x0},
- {10, 0x3},
- {0, 0x2} };
/* SDIO Drive Strength to sel value table for PMU Rev 13 (1.8v) */
static const sdiod_drive_str_t sdiod_drive_strength_tab5_1v8[] = {
@@ -125,14 +107,6 @@ static const sdiod_drive_str_t sdiod_drive_strength_tab5_1v8[] = {
{0, 0x0} };
/* SDIO Drive Strength to sel value table for PMU Rev 13 (3.3v) */
-static const sdiod_drive_str_t sdiod_drive_strength_tab5_3v3[] = {
- {12, 0x7},
- {10, 0x6},
- {8, 0x5},
- {6, 0x4},
- {4, 0x2},
- {2, 0x1},
- {0, 0x0} };
#define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu))
diff --git a/drivers/net/wireless/bcmdhd/include/Makefile b/drivers/net/wireless/bcmdhd/include/Makefile
index c07266fd6fdc..67c4906f5889 100644
--- a/drivers/net/wireless/bcmdhd/include/Makefile
+++ b/drivers/net/wireless/bcmdhd/include/Makefile
@@ -10,7 +10,7 @@
#
# Copyright 2005, Broadcom, Inc.
#
-# $Id: Makefile 241702 2011-02-19 00:41:03Z automrgr $
+# $Id: Makefile 241702 2011-02-19 00:41:03Z $
#
SRCBASE := ..
diff --git a/drivers/net/wireless/bcmdhd/include/aidmp.h b/drivers/net/wireless/bcmdhd/include/aidmp.h
index 375df443a29a..b993a033abc2 100644
--- a/drivers/net/wireless/bcmdhd/include/aidmp.h
+++ b/drivers/net/wireless/bcmdhd/include/aidmp.h
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: aidmp.h,v 13.4.14.1 2010-03-09 18:40:06 Exp $
+ * $Id: aidmp.h 277737 2011-08-16 17:54:59Z $
*/
diff --git a/drivers/net/wireless/bcmdhd/include/bcmcdc.h b/drivers/net/wireless/bcmdhd/include/bcmcdc.h
index ce45c50d9641..77a20f87b7ea 100644
--- a/drivers/net/wireless/bcmdhd/include/bcmcdc.h
+++ b/drivers/net/wireless/bcmdhd/include/bcmcdc.h
@@ -24,7 +24,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: bcmcdc.h,v 13.25.10.3 2010-12-22 23:47:26 Exp $
+ * $Id: bcmcdc.h 277737 2011-08-16 17:54:59Z $
*/
#ifndef _bcmcdc_h_
diff --git a/drivers/net/wireless/bcmdhd/include/bcmdefs.h b/drivers/net/wireless/bcmdhd/include/bcmdefs.h
index da1fd5e4eac4..17cc0e955f62 100644
--- a/drivers/net/wireless/bcmdhd/include/bcmdefs.h
+++ b/drivers/net/wireless/bcmdhd/include/bcmdefs.h
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: bcmdefs.h,v 13.68.2.8 2011-01-08 04:04:19 Exp $
+ * $Id: bcmdefs.h 279282 2011-08-23 22:44:02Z $
*/
@@ -30,12 +30,26 @@
+
+#define BCM_REFERENCE(data) ((void)(data))
+
+
+
#define bcmreclaimed 0
#define _data _data
#define _fn _fn
+#define BCMPREATTACHDATA(_data) _data
+#define BCMPREATTACHFN(_fn) _fn
#define _data _data
#define _fn _fn
#define _fn _fn
+#define BCMNMIATTACHFN(_fn) _fn
+#define BCMNMIATTACHDATA(_data) _data
+#define BCMOVERLAY0DATA(_sym) _sym
+#define BCMOVERLAY0FN(_fn) _fn
+#define BCMOVERLAY1DATA(_sym) _sym
+#define BCMOVERLAY1FN(_fn) _fn
+#define BCMOVERLAYERRFN(_fn) _fn
#define CONST const
#define BCMFASTPATH
@@ -43,9 +57,30 @@
#define _data _data
+#define BCMROMDAT_NAME(_data) _data
#define _fn _fn
#define _fn _fn
#define STATIC static
+#define BCMROMDAT_ARYSIZ(data) ARRAYSIZE(data)
+#define BCMROMDAT_SIZEOF(data) sizeof(data)
+#define BCMROMDAT_APATCH(data)
+#define BCMROMDAT_SPATCH(data)
+
+
+
+#define OVERLAY_INLINE
+#define OSTATIC static
+#define BCMOVERLAYDATA(_ovly, _sym) _sym
+#define BCMOVERLAYFN(_ovly, _fn) _fn
+#define BCMOVERLAYERRFN(_fn) _fn
+#define BCMROMOVERLAYDATA(_ovly, _data) _data
+#define BCMROMOVERLAYFN(_ovly, _fn) _fn
+#define BCMATTACHOVERLAYDATA(_ovly, _sym) _sym
+#define BCMATTACHOVERLAYFN(_ovly, _fn) _fn
+#define BCMINITOVERLAYDATA(_ovly, _sym) _sym
+#define BCMINITOVERLAYFN(_ovly, _fn) _fn
+#define BCMUNINITOVERLAYFN(_ovly, _fn) _fn
+
#define SI_BUS 0
diff --git a/drivers/net/wireless/bcmdhd/include/bcmdevs.h b/drivers/net/wireless/bcmdhd/include/bcmdevs.h
index 4f707c0c6920..287f1c65fc9a 100644
--- a/drivers/net/wireless/bcmdhd/include/bcmdevs.h
+++ b/drivers/net/wireless/bcmdhd/include/bcmdevs.h
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: bcmdevs.h,v 13.285.2.39 2011-02-04 05:03:16 Exp $
+ * $Id: bcmdevs.h 295140 2011-11-09 17:22:01Z $
*/
@@ -31,7 +31,16 @@
#define VENDOR_EPIGRAM 0xfeda
#define VENDOR_BROADCOM 0x14e4
+#define VENDOR_3COM 0x10b7
+#define VENDOR_NETGEAR 0x1385
+#define VENDOR_DIAMOND 0x1092
+#define VENDOR_INTEL 0x8086
+#define VENDOR_DELL 0x1028
+#define VENDOR_HP 0x103c
+#define VENDOR_HP_COMPAQ 0x0e11
+#define VENDOR_APPLE 0x106b
#define VENDOR_SI_IMAGE 0x1095
+#define VENDOR_BUFFALO 0x1154
#define VENDOR_TI 0x104c
#define VENDOR_RICOH 0x1180
#define VENDOR_JMICRON 0x197b
@@ -54,9 +63,38 @@
#define BCM_DNGL_BL_PID_43239 0xbd1b
#define BCM_DNGL_BDC_PID 0x0bdc
#define BCM_DNGL_JTAG_PID 0x4a44
+#define BCM_DNGL_BL_PID_4324 0xbd1c
+
+
+#define BCM_HWUSB_PID_43239 43239
+
+
+#define BCM4210_DEVICE_ID 0x1072
+#define BCM4230_DEVICE_ID 0x1086
+#define BCM4401_ENET_ID 0x170c
+#define BCM3352_DEVICE_ID 0x3352
+#define BCM3360_DEVICE_ID 0x3360
+#define BCM4211_DEVICE_ID 0x4211
+#define BCM4231_DEVICE_ID 0x4231
+#define BCM4303_D11B_ID 0x4303
+#define BCM4311_D11G_ID 0x4311
+#define BCM4311_D11DUAL_ID 0x4312
+#define BCM4311_D11A_ID 0x4313
+#define BCM4328_D11DUAL_ID 0x4314
+#define BCM4328_D11G_ID 0x4315
+#define BCM4328_D11A_ID 0x4316
+#define BCM4318_D11G_ID 0x4318
+#define BCM4318_D11DUAL_ID 0x4319
+#define BCM4318_D11A_ID 0x431a
#define BCM4325_D11DUAL_ID 0x431b
#define BCM4325_D11G_ID 0x431c
#define BCM4325_D11A_ID 0x431d
+#define BCM4306_D11G_ID 0x4320
+#define BCM4306_D11A_ID 0x4321
+#define BCM4306_UART_ID 0x4322
+#define BCM4306_V90_ID 0x4323
+#define BCM4306_D11DUAL_ID 0x4324
+#define BCM4306_D11G_ID2 0x4325
#define BCM4321_D11N_ID 0x4328
#define BCM4321_D11N2G_ID 0x4329
#define BCM4321_D11N5G_ID 0x432a
@@ -98,17 +136,58 @@
#define BCM43237_D11N5G_ID 0x4356
#define BCM43227_D11N2G_ID 0x4358
#define BCM43228_D11N_ID 0x4359
-#define BCM43228_D11N5G_ID 0x435a
+#define BCM43228_D11N5G_ID 0x435a
#define BCM43362_D11N_ID 0x4363
#define BCM43239_D11N_ID 0x4370
+#define BCM4324_D11N_ID 0x4374
+#define BCM43217_D11N2G_ID 0x43a9
+#define BCM43131_D11N2G_ID 0x43aa
+#define BCM4314_D11N2G_ID 0x4364
+#define BCM43142_D11N2G_ID 0x4365
+#define BCMGPRS_UART_ID 0x4333
+#define BCMGPRS2_UART_ID 0x4344
+#define FPGA_JTAGM_ID 0x43f0
+#define BCM_JTAGM_ID 0x43f1
#define SDIOH_FPGA_ID 0x43f2
+#define BCM_SDIOH_ID 0x43f3
+#define SDIOD_FPGA_ID 0x43f4
#define SPIH_FPGA_ID 0x43f5
+#define BCM_SPIH_ID 0x43f6
+#define MIMO_FPGA_ID 0x43f8
+#define BCM_JTAGM2_ID 0x43f9
+#define SDHCI_FPGA_ID 0x43fa
+#define BCM4402_ENET_ID 0x4402
+#define BCM4402_V90_ID 0x4403
+#define BCM4410_DEVICE_ID 0x4410
+#define BCM4412_DEVICE_ID 0x4412
+#define BCM4430_DEVICE_ID 0x4430
+#define BCM4432_DEVICE_ID 0x4432
+#define BCM4704_ENET_ID 0x4706
#define BCM4710_DEVICE_ID 0x4710
+#define BCM47XX_AUDIO_ID 0x4711
+#define BCM47XX_V90_ID 0x4712
+#define BCM47XX_ENET_ID 0x4713
+#define BCM47XX_EXT_ID 0x4714
+#define BCM47XX_GMAC_ID 0x4715
+#define BCM47XX_USBH_ID 0x4716
+#define BCM47XX_USBD_ID 0x4717
+#define BCM47XX_IPSEC_ID 0x4718
+#define BCM47XX_ROBO_ID 0x4719
+#define BCM47XX_USB20H_ID 0x471a
+#define BCM47XX_USB20D_ID 0x471b
+#define BCM47XX_ATA100_ID 0x471d
+#define BCM47XX_SATAXOR_ID 0x471e
+#define BCM47XX_GIGETH_ID 0x471f
+#define BCM4712_MIPS_ID 0x4720
+#define BCM4716_DEVICE_ID 0x4722
+#define BCM47XX_SMBUS_EMU_ID 0x47fe
+#define BCM47XX_XOR_EMU_ID 0x47ff
+#define EPI41210_DEVICE_ID 0xa0fa
+#define EPI41230_DEVICE_ID 0xa10e
+#define JINVANI_SDIOH_ID 0x4743
#define BCM27XX_SDIOH_ID 0x2702
-#define PCIXX21_FLASHMEDIA0_ID 0x8033
-#define PCIXX21_SDIOH0_ID 0x8034
#define PCIXX21_FLASHMEDIA_ID 0x803b
#define PCIXX21_SDIOH_ID 0x803c
#define R5C822_SDIOH_ID 0x0822
@@ -121,11 +200,13 @@
#define BCM43112_CHIP_ID 43112
#define BCM4312_CHIP_ID 0x4312
#define BCM4313_CHIP_ID 0x4313
+#define BCM43131_CHIP_ID 43131
#define BCM4315_CHIP_ID 0x4315
#define BCM4318_CHIP_ID 0x4318
#define BCM4319_CHIP_ID 0x4319
#define BCM4320_CHIP_ID 0x4320
#define BCM4321_CHIP_ID 0x4321
+#define BCM43217_CHIP_ID 43217
#define BCM4322_CHIP_ID 0x4322
#define BCM43221_CHIP_ID 43221
#define BCM43222_CHIP_ID 43222
@@ -152,15 +233,28 @@
#define BCM4336_CHIP_ID 0x4336
#define BCM43362_CHIP_ID 43362
#define BCM4330_CHIP_ID 0x4330
+#define BCM6362_CHIP_ID 0x6362
+#define BCM4314_CHIP_ID 0x4314
+#define BCM43142_CHIP_ID 43142
+#define BCM4324_CHIP_ID 0x4324
+
+#define BCM4342_CHIP_ID 4342
#define BCM4402_CHIP_ID 0x4402
#define BCM4704_CHIP_ID 0x4704
#define BCM4710_CHIP_ID 0x4710
#define BCM4712_CHIP_ID 0x4712
+#define BCM4716_CHIP_ID 0x4716
+#define BCM47162_CHIP_ID 47162
+#define BCM4748_CHIP_ID 0x4748
+#define BCM4749_CHIP_ID 0x4749
#define BCM4785_CHIP_ID 0x4785
#define BCM5350_CHIP_ID 0x5350
#define BCM5352_CHIP_ID 0x5352
#define BCM5354_CHIP_ID 0x5354
#define BCM5365_CHIP_ID 0x5365
+#define BCM5356_CHIP_ID 0x5356
+#define BCM5357_CHIP_ID 0x5357
+#define BCM53572_CHIP_ID 53572
#define BCM4303_PKG_ID 2
@@ -175,8 +269,478 @@
#define BCM4329_289PIN_PKG_ID 0
#define BCM4329_182PIN_PKG_ID 1
#define BCM5354E_PKG_ID 1
+#define BCM4716_PKG_ID 8
+#define BCM4717_PKG_ID 9
+#define BCM4718_PKG_ID 10
+#define BCM5356_PKG_NONMODE 1
+#define BCM5358U_PKG_ID 8
+#define BCM5358_PKG_ID 9
+#define BCM47186_PKG_ID 10
+#define BCM5357_PKG_ID 11
+#define BCM5356U_PKG_ID 12
+#define BCM53572_PKG_ID 8
+#define BCM47188_PKG_ID 9
+#define BCM4331TT_PKG_ID 8
+#define BCM4331TN_PKG_ID 9
+#define BCM4331TNA0_PKG_ID 0xb
+
+
#define HDLSIM5350_PKG_ID 1
#define HDLSIM_PKG_ID 14
#define HWSIM_PKG_ID 15
+#define BCM43224_FAB_CSM 0x8
+#define BCM43224_FAB_SMIC 0xa
+#define BCM4336_WLBGA_PKG_ID 0x8
+#define BCM4330_WLBGA_PKG_ID 0x0
+#define BCM4314PCIE_ARM_PKG_ID (8 | 0)
+#define BCM4314SDIO_PKG_ID (8 | 1)
+#define BCM4314PCIE_PKG_ID (8 | 2)
+#define BCM4314SDIO_ARM_PKG_ID (8 | 3)
+#define BCM4314SDIO_FPBGA_PKG_ID (8 | 4)
+#define BCM4314DEV_PKG_ID (8 | 6)
+
+#define PCIXX21_FLASHMEDIA0_ID 0x8033
+#define PCIXX21_SDIOH0_ID 0x8034
+
+
+#define BFL_BTC2WIRE 0x00000001
+#define BFL_BTCOEX 0x00000001
+#define BFL_PACTRL 0x00000002
+#define BFL_AIRLINEMODE 0x00000004
+#define BFL_ADCDIV 0x00000008
+#define BFL_ENETROBO 0x00000010
+#define BFL_NOPLLDOWN 0x00000020
+#define BFL_CCKHIPWR 0x00000040
+#define BFL_ENETADM 0x00000080
+#define BFL_ENETVLAN 0x00000100
+#ifdef WLAFTERBURNER
+#define BFL_AFTERBURNER 0x00000200
+#endif
+#define BFL_NOPCI 0x00000400
+#define BFL_FEM 0x00000800
+#define BFL_EXTLNA 0x00001000
+#define BFL_HGPA 0x00002000
+#define BFL_BTC2WIRE_ALTGPIO 0x00004000
+#define BFL_ALTIQ 0x00008000
+#define BFL_NOPA 0x00010000
+#define BFL_RSSIINV 0x00020000
+#define BFL_PAREF 0x00040000
+#define BFL_3TSWITCH 0x00080000
+#define BFL_PHASESHIFT 0x00100000
+#define BFL_BUCKBOOST 0x00200000
+#define BFL_FEM_BT 0x00400000
+#define BFL_NOCBUCK 0x00800000
+#define BFL_CCKFAVOREVM 0x01000000
+#define BFL_PALDO 0x02000000
+#define BFL_LNLDO2_2P5 0x04000000
+#define BFL_FASTPWR 0x08000000
+#define BFL_UCPWRCTL_MININDX 0x08000000
+#define BFL_EXTLNA_5GHz 0x10000000
+#define BFL_TRSW_1by2 0x20000000
+#define BFL_LO_TRSW_R_5GHz 0x40000000
+#define BFL_ELNA_GAINDEF 0x80000000
+#define BFL_EXTLNA_TX 0x20000000
+
+
+#define BFL2_RXBB_INT_REG_DIS 0x00000001
+#define BFL2_APLL_WAR 0x00000002
+#define BFL2_TXPWRCTRL_EN 0x00000004
+#define BFL2_2X4_DIV 0x00000008
+#define BFL2_5G_PWRGAIN 0x00000010
+#define BFL2_PCIEWAR_OVR 0x00000020
+#define BFL2_CAESERS_BRD 0x00000040
+#define BFL2_BTC3WIRE 0x00000080
+#define BFL2_BTCLEGACY 0x00000080
+#define BFL2_SKWRKFEM_BRD 0x00000100
+#define BFL2_SPUR_WAR 0x00000200
+#define BFL2_GPLL_WAR 0x00000400
+#define BFL2_TRISTATE_LED 0x00000800
+#define BFL2_SINGLEANT_CCK 0x00001000
+#define BFL2_2G_SPUR_WAR 0x00002000
+#define BFL2_BPHY_ALL_TXCORES 0x00004000
+#define BFL2_FCC_BANDEDGE_WAR 0x00008000
+#define BFL2_GPLL_WAR2 0x00010000
+#define BFL2_IPALVLSHIFT_3P3 0x00020000
+#define BFL2_INTERNDET_TXIQCAL 0x00040000
+#define BFL2_XTALBUFOUTEN 0x00080000
+#define BFL2_ANAPACTRL_2G 0x00100000
+#define BFL2_ANAPACTRL_5G 0x00200000
+#define BFL2_ELNACTRL_TRSW_2G 0x00400000
+#define BFL2_BT_SHARE_ANT0 0x00800000
+#define BFL2_TEMPSENSE_HIGHER 0x01000000
+#define BFL2_BTC3WIREONLY 0x02000000
+#define BFL2_PWR_NOMINAL 0x04000000
+#define BFL2_EXTLNA_TX 0x08000000
+
+#define BFL2_4313_RADIOREG 0x10000000
+
+
+
+#define BOARD_GPIO_BTC3W_IN 0x850
+#define BOARD_GPIO_BTC3W_OUT 0x020
+#define BOARD_GPIO_BTCMOD_IN 0x010
+#define BOARD_GPIO_BTCMOD_OUT 0x020
+#define BOARD_GPIO_BTC_IN 0x080
+#define BOARD_GPIO_BTC_OUT 0x100
+#define BOARD_GPIO_PACTRL 0x200
+#define BOARD_GPIO_12 0x1000
+#define BOARD_GPIO_13 0x2000
+#define BOARD_GPIO_BTC4_IN 0x0800
+#define BOARD_GPIO_BTC4_BT 0x2000
+#define BOARD_GPIO_BTC4_STAT 0x4000
+#define BOARD_GPIO_BTC4_WLAN 0x8000
+#define BOARD_GPIO_1_WLAN_PWR 0x2
+#define BOARD_GPIO_4_WLAN_PWR 0x10
+
+#define GPIO_BTC4W_OUT_4312 0x010
+#define GPIO_BTC4W_OUT_43224 0x020
+#define GPIO_BTC4W_OUT_43224_SHARED 0x0e0
+#define GPIO_BTC4W_OUT_43225 0x0e0
+#define GPIO_BTC4W_OUT_43421 0x020
+#define GPIO_BTC4W_OUT_4313 0x060
+
+#define PCI_CFG_GPIO_SCS 0x10
+#define PCI_CFG_GPIO_HWRAD 0x20
+#define PCI_CFG_GPIO_XTAL 0x40
+#define PCI_CFG_GPIO_PLL 0x80
+
+
+#define PLL_DELAY 150
+#define FREF_DELAY 200
+#define MIN_SLOW_CLK 32
+#define XTAL_ON_DELAY 1000
+
+
+#define BU4710_BOARD 0x0400
+#define VSIM4710_BOARD 0x0401
+#define QT4710_BOARD 0x0402
+
+#define BU4309_BOARD 0x040a
+#define BCM94309CB_BOARD 0x040b
+#define BCM94309MP_BOARD 0x040c
+#define BCM4309AP_BOARD 0x040d
+
+#define BCM94302MP_BOARD 0x040e
+
+#define BU4306_BOARD 0x0416
+#define BCM94306CB_BOARD 0x0417
+#define BCM94306MP_BOARD 0x0418
+
+#define BCM94710D_BOARD 0x041a
+#define BCM94710R1_BOARD 0x041b
+#define BCM94710R4_BOARD 0x041c
+#define BCM94710AP_BOARD 0x041d
+
+#define BU2050_BOARD 0x041f
+
+#define BCM94306P50_BOARD 0x0420
+
+#define BCM94309G_BOARD 0x0421
+
+#define BU4704_BOARD 0x0423
+#define BU4702_BOARD 0x0424
+
+#define BCM94306PC_BOARD 0x0425
+
+#define MPSG4306_BOARD 0x0427
+
+#define BCM94702MN_BOARD 0x0428
+
+
+#define BCM94702CPCI_BOARD 0x0429
+
+
+#define BCM95380RR_BOARD 0x042a
+
+
+#define BCM94306CBSG_BOARD 0x042b
+
+
+#define PCSG94306_BOARD 0x042d
+
+
+#define BU4704SD_BOARD 0x042e
+
+
+#define BCM94704AGR_BOARD 0x042f
+
+
+#define BCM94308MP_BOARD 0x0430
+
+
+#define BCM94306GPRS_BOARD 0x0432
+
+
+#define BU5365_FPGA_BOARD 0x0433
+
+#define BU4712_BOARD 0x0444
+#define BU4712SD_BOARD 0x045d
+#define BU4712L_BOARD 0x045f
+
+
+#define BCM94712AP_BOARD 0x0445
+#define BCM94712P_BOARD 0x0446
+
+
+#define BU4318_BOARD 0x0447
+#define CB4318_BOARD 0x0448
+#define MPG4318_BOARD 0x0449
+#define MP4318_BOARD 0x044a
+#define SD4318_BOARD 0x044b
+
+
+#define BCM94313BU_BOARD 0x050f
+#define BCM94313HM_BOARD 0x0510
+#define BCM94313EPA_BOARD 0x0511
+#define BCM94313HMG_BOARD 0x051C
+
+
+#define BCM96338_BOARD 0x6338
+#define BCM96348_BOARD 0x6348
+#define BCM96358_BOARD 0x6358
+#define BCM96368_BOARD 0x6368
+
+
+#define BCM94306P_BOARD 0x044c
+
+
+#define BCM94303MP_BOARD 0x044e
+
+
+#define BCM94306MPSGH_BOARD 0x044f
+
+
+#define BCM94306MPM 0x0450
+#define BCM94306MPL 0x0453
+
+
+#define BCM94712AGR_BOARD 0x0451
+
+
+#define PC4303_BOARD 0x0454
+
+
+#define BCM95350K_BOARD 0x0455
+
+
+#define BCM95350R_BOARD 0x0456
+
+
+#define BCM94306MPLNA_BOARD 0x0457
+
+
+#define BU4320_BOARD 0x0458
+#define BU4320S_BOARD 0x0459
+#define BCM94320PH_BOARD 0x045a
+
+
+#define BCM94306MPH_BOARD 0x045b
+
+
+#define BCM94306PCIV_BOARD 0x045c
+
+#define BU4712SD_BOARD 0x045d
+
+#define BCM94320PFLSH_BOARD 0x045e
+
+#define BU4712L_BOARD 0x045f
+#define BCM94712LGR_BOARD 0x0460
+#define BCM94320R_BOARD 0x0461
+
+#define BU5352_BOARD 0x0462
+
+#define BCM94318MPGH_BOARD 0x0463
+
+#define BU4311_BOARD 0x0464
+#define BCM94311MC_BOARD 0x0465
+#define BCM94311MCAG_BOARD 0x0466
+
+#define BCM95352GR_BOARD 0x0467
+
+
+#define BCM95351AGR_BOARD 0x0470
+
+
+#define BCM94704MPCB_BOARD 0x0472
+
+
+#define BU4785_BOARD 0x0478
+
+
+#define BU4321_BOARD 0x046b
+#define BU4321E_BOARD 0x047c
+#define MP4321_BOARD 0x046c
+#define CB2_4321_BOARD 0x046d
+#define CB2_4321_AG_BOARD 0x0066
+#define MC4321_BOARD 0x046e
+
+
+#define BU4328_BOARD 0x0481
+#define BCM4328SDG_BOARD 0x0482
+#define BCM4328SDAG_BOARD 0x0483
+#define BCM4328UG_BOARD 0x0484
+#define BCM4328UAG_BOARD 0x0485
+#define BCM4328PC_BOARD 0x0486
+#define BCM4328CF_BOARD 0x0487
+
+
+#define BCM94325DEVBU_BOARD 0x0490
+#define BCM94325BGABU_BOARD 0x0491
+
+#define BCM94325SDGWB_BOARD 0x0492
+
+#define BCM94325SDGMDL_BOARD 0x04aa
+#define BCM94325SDGMDL2_BOARD 0x04c6
+#define BCM94325SDGMDL3_BOARD 0x04c9
+
+#define BCM94325SDABGWBA_BOARD 0x04e1
+
+
+#define BCM94322MC_SSID 0x04a4
+#define BCM94322USB_SSID 0x04a8
+#define BCM94322HM_SSID 0x04b0
+#define BCM94322USB2D_SSID 0x04bf
+
+
+#define BCM4312MCGSG_BOARD 0x04b5
+
+
+#define BCM94315DEVBU_SSID 0x04c2
+#define BCM94315USBGP_SSID 0x04c7
+#define BCM94315BGABU_SSID 0x04ca
+#define BCM94315USBGP41_SSID 0x04cb
+
+
+#define BCM94319DEVBU_SSID 0X04e5
+#define BCM94319USB_SSID 0X04e6
+#define BCM94319SD_SSID 0X04e7
+
+
+#define BCM94716NR2_SSID 0x04cd
+
+
+#define BCM94319DEVBU_SSID 0X04e5
+#define BCM94319USBNP4L_SSID 0X04e6
+#define BCM94319WLUSBN4L_SSID 0X04e7
+#define BCM94319SDG_SSID 0X04ea
+#define BCM94319LCUSBSDN4L_SSID 0X04eb
+#define BCM94319USBB_SSID 0x04ee
+#define BCM94319LCSDN4L_SSID 0X0507
+#define BCM94319LSUSBN4L_SSID 0X0508
+#define BCM94319SDNA4L_SSID 0X0517
+#define BCM94319SDELNA4L_SSID 0X0518
+#define BCM94319SDELNA6L_SSID 0X0539
+#define BCM94319ARCADYAN_SSID 0X0546
+#define BCM94319WINDSOR_SSID 0x0561
+#define BCM94319MLAP_SSID 0x0562
+#define BCM94319SDNA_SSID 0x058b
+#define BCM94319BHEMU3_SSID 0x0563
+#define BCM94319SDHMB_SSID 0x058c
+#define BCM94319SDBREF_SSID 0x05a1
+#define BCM94319USBSDB_SSID 0x05a2
+
+
+
+#define BCM94329AGB_SSID 0X04b9
+#define BCM94329TDKMDL1_SSID 0X04ba
+#define BCM94329TDKMDL11_SSID 0X04fc
+#define BCM94329OLYMPICN18_SSID 0X04fd
+#define BCM94329OLYMPICN90_SSID 0X04fe
+#define BCM94329OLYMPICN90U_SSID 0X050c
+#define BCM94329OLYMPICN90M_SSID 0X050b
+#define BCM94329AGBF_SSID 0X04ff
+#define BCM94329OLYMPICX17_SSID 0X0504
+#define BCM94329OLYMPICX17M_SSID 0X050a
+#define BCM94329OLYMPICX17U_SSID 0X0509
+#define BCM94329OLYMPICUNO_SSID 0X0564
+#define BCM94329MOTOROLA_SSID 0X0565
+#define BCM94329OLYMPICLOCO_SSID 0X0568
+
+#define BCM94336SD_WLBGABU_SSID 0x0511
+#define BCM94336SD_WLBGAREF_SSID 0x0519
+#define BCM94336SDGP_SSID 0x0538
+#define BCM94336SDG_SSID 0x0519
+#define BCM94336SDGN_SSID 0x0538
+#define BCM94336SDGFC_SSID 0x056B
+
+
+#define BCM94330SDG_SSID 0x0528
+#define BCM94330SD_FCBGABU_SSID 0x052e
+#define BCM94330SD_WLBGABU_SSID 0x052f
+#define BCM94330SD_FCBGA_SSID 0x0530
+#define BCM94330FCSDAGB_SSID 0x0532
+#define BCM94330OLYMPICAMG_SSID 0x0549
+#define BCM94330OLYMPICAMGEPA_SSID 0x054F
+#define BCM94330OLYMPICUNO3_SSID 0x0551
+#define BCM94330WLSDAGB_SSID 0x0547
+#define BCM94330CSPSDAGBB_SSID 0x054A
+
+
+#define BCM943224X21 0x056e
+#define BCM943224X21_FCC 0x00d1
+
+
+#define BCM943228BU8_SSID 0x0540
+#define BCM943228BU9_SSID 0x0541
+#define BCM943228BU_SSID 0x0542
+#define BCM943227HM4L_SSID 0x0543
+#define BCM943227HMB_SSID 0x0544
+#define BCM943228HM4L_SSID 0x0545
+#define BCM943228SD_SSID 0x0573
+
+
+#define BCM943239MOD_SSID 0x05ac
+#define BCM943239REF_SSID 0x05aa
+
+
+#define BCM94331X19 0x00D6
+#define BCM94331PCIEBT3Ax_SSID 0x00E4
+#define BCM94331X12_2G_SSID 0x00EC
+#define BCM94331X12_5G_SSID 0x00ED
+#define BCM94331X29B 0x00EF
+#define BCM94331BU_SSID 0x0523
+#define BCM94331S9BU_SSID 0x0524
+#define BCM94331MC_SSID 0x0525
+#define BCM94331MCI_SSID 0x0526
+#define BCM94331PCIEBT4_SSID 0x0527
+#define BCM94331HM_SSID 0x0574
+#define BCM94331PCIEDUAL_SSID 0x059B
+#define BCM94331MCH5_SSID 0x05A9
+#define BCM94331PCIEDUALV2_SSID 0x05B7
+#define BCM94331CS_SSID 0x05C6
+#define BCM94331CSAX_SSID 0x00EF
+
+
+#define BCM953572BU_SSID 0x058D
+#define BCM953572NR2_SSID 0x058E
+#define BCM947188NR2_SSID 0x058F
+#define BCM953572SDRNR2_SSID 0x0590
+
+
+#define BCM943236OLYMPICSULLEY_SSID 0x594
+#define BCM943236PREPROTOBLU2O3_SSID 0x5b9
+#define BCM943236USBELNA_SSID 0x5f8
+
+
+#define GPIO_NUMPINS 32
+
+
+#define RDL_RAM_BASE_4319 0x60000000
+#define RDL_RAM_BASE_4329 0x60000000
+#define RDL_RAM_SIZE_4319 0x48000
+#define RDL_RAM_SIZE_4329 0x48000
+#define RDL_RAM_SIZE_43236 0x70000
+#define RDL_RAM_BASE_43236 0x60000000
+#define RDL_RAM_SIZE_4328 0x60000
+#define RDL_RAM_BASE_4328 0x80000000
+#define RDL_RAM_SIZE_4322 0x60000
+#define RDL_RAM_BASE_4322 0x60000000
+
+
+#define MUXENAB_UART 0x00000001
+#define MUXENAB_GPIO 0x00000002
+#define MUXENAB_ERCX 0x00000004
+#define MUXENAB_JTAG 0x00000008
+#define MUXENAB_HOST_WAKE 0x00000010
#endif
diff --git a/drivers/net/wireless/bcmdhd/include/bcmendian.h b/drivers/net/wireless/bcmdhd/include/bcmendian.h
index 04b07ecb8043..f3356a724b44 100644
--- a/drivers/net/wireless/bcmdhd/include/bcmendian.h
+++ b/drivers/net/wireless/bcmdhd/include/bcmendian.h
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: bcmendian.h,v 1.36 2009-11-09 05:29:43 Exp $
+ * $Id: bcmendian.h 277737 2011-08-16 17:54:59Z $
*
* This file by default provides proper behavior on little-endian architectures.
* On big-endian architectures, IL_BIGENDIAN should be defined.
diff --git a/drivers/net/wireless/bcmdhd/include/bcmpcispi.h b/drivers/net/wireless/bcmdhd/include/bcmpcispi.h
index fd148c591d88..51e0427e7f60 100644
--- a/drivers/net/wireless/bcmdhd/include/bcmpcispi.h
+++ b/drivers/net/wireless/bcmdhd/include/bcmpcispi.h
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: bcmpcispi.h,v 13.15.112.1 2010-11-15 18:22:12 Exp $
+ * $Id: bcmpcispi.h 277737 2011-08-16 17:54:59Z $
*/
#ifndef _BCM_PCI_SPI_H
#define _BCM_PCI_SPI_H
diff --git a/drivers/net/wireless/bcmdhd/include/bcmperf.h b/drivers/net/wireless/bcmdhd/include/bcmperf.h
index a3985cf29375..a503edbd6226 100644
--- a/drivers/net/wireless/bcmdhd/include/bcmperf.h
+++ b/drivers/net/wireless/bcmdhd/include/bcmperf.h
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: bcmperf.h,v 13.5 2007-09-14 22:00:59 Exp $
+ * $Id: bcmperf.h 277737 2011-08-16 17:54:59Z $
*/
/* essai */
#ifndef _BCMPERF_H_
diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdbus.h b/drivers/net/wireless/bcmdhd/include/bcmsdbus.h
index 5fda5e9b5df4..21a58b473e91 100644
--- a/drivers/net/wireless/bcmdhd/include/bcmsdbus.h
+++ b/drivers/net/wireless/bcmdhd/include/bcmsdbus.h
@@ -22,7 +22,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: bcmsdbus.h,v 13.17.86.2 2010-12-23 01:13:20 Exp $
+ * $Id: bcmsdbus.h 300017 2011-12-01 20:30:27Z $
*/
#ifndef _sdio_api_h_
@@ -117,4 +117,12 @@ void *bcmsdh_get_sdioh(bcmsdh_info_t *sdh);
+extern SDIOH_API_RC sdioh_sleep(sdioh_info_t *si, bool enab);
+
+/* GPIO support */
+extern SDIOH_API_RC sdioh_gpio_init(sdioh_info_t *sd);
+extern bool sdioh_gpioin(sdioh_info_t *sd, uint32 gpio);
+extern SDIOH_API_RC sdioh_gpioouten(sdioh_info_t *sd, uint32 gpio);
+extern SDIOH_API_RC sdioh_gpioout(sdioh_info_t *sd, uint32 gpio, bool enab);
+
#endif /* _sdio_api_h_ */
diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdh.h b/drivers/net/wireless/bcmdhd/include/bcmsdh.h
index 4e3affde6b06..72ee65da8874 100644
--- a/drivers/net/wireless/bcmdhd/include/bcmsdh.h
+++ b/drivers/net/wireless/bcmdhd/include/bcmsdh.h
@@ -23,7 +23,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: bcmsdh.h,v 13.46.52.3 2010-10-19 00:41:44 Exp $
+ * $Id: bcmsdh.h 300017 2011-12-01 20:30:27Z $
*/
#ifndef _bcmsdh_h_
@@ -208,4 +208,12 @@ extern uint32 bcmsdh_cur_sbwad(void *sdh);
extern void bcmsdh_chipinfo(void *sdh, uint32 chip, uint32 chiprev);
+extern int bcmsdh_sleep(void *sdh, bool enab);
+
+/* GPIO support */
+extern int bcmsdh_gpio_init(void *sd);
+extern bool bcmsdh_gpioin(void *sd, uint32 gpio);
+extern int bcmsdh_gpioouten(void *sd, uint32 gpio);
+extern int bcmsdh_gpioout(void *sd, uint32 gpio, bool enab);
+
#endif /* _bcmsdh_h_ */
diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h b/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h
index d188c4ec7d5a..db8ea596304c 100644
--- a/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h
+++ b/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: bcmsdh_sdmmc.h,v 13.5.88.1 2010-12-23 01:13:20 Exp $
+ * $Id: bcmsdh_sdmmc.h 314048 2012-02-09 20:31:56Z $
*/
#ifndef __BCMSDH_SDMMC_H__
@@ -82,9 +82,10 @@ struct sdioh_info {
uint8 num_funcs; /* Supported funcs on client */
uint32 com_cis_ptr;
uint32 func_cis_ptr[SDIOD_MAX_IOFUNCS];
- uint max_dma_len;
- uint max_dma_descriptors; /* DMA Descriptors supported by this controller. */
-// SDDMA_DESCRIPTOR SGList[32]; /* Scatter/Gather DMA List */
+
+#define SDIOH_SDMMC_MAX_SG_ENTRIES 32
+ struct scatterlist sg_list[SDIOH_SDMMC_MAX_SG_ENTRIES];
+ bool use_rxchain;
};
/************************************************************
diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdpcm.h b/drivers/net/wireless/bcmdhd/include/bcmsdpcm.h
index ee29b5c08a5c..1b9d39fee8fc 100644
--- a/drivers/net/wireless/bcmdhd/include/bcmsdpcm.h
+++ b/drivers/net/wireless/bcmdhd/include/bcmsdpcm.h
@@ -22,7 +22,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: bcmsdpcm.h,v 13.4.90.2 2010-05-12 04:14:25 Exp $
+ * $Id: bcmsdpcm.h 277737 2011-08-16 17:54:59Z $
*/
#ifndef _bcmsdpcm_h_
diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdspi.h b/drivers/net/wireless/bcmdhd/include/bcmsdspi.h
index 0bff355f8ffd..a62bee42b2ba 100644
--- a/drivers/net/wireless/bcmdhd/include/bcmsdspi.h
+++ b/drivers/net/wireless/bcmdhd/include/bcmsdspi.h
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: bcmsdspi.h,v 13.11.86.1 2010-11-15 18:14:56 Exp $
+ * $Id: bcmsdspi.h 277737 2011-08-16 17:54:59Z $
*/
#ifndef _BCM_SD_SPI_H
#define _BCM_SD_SPI_H
diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdstd.h b/drivers/net/wireless/bcmdhd/include/bcmsdstd.h
index 0f4c0267dbc8..c7382540b84f 100644
--- a/drivers/net/wireless/bcmdhd/include/bcmsdstd.h
+++ b/drivers/net/wireless/bcmdhd/include/bcmsdstd.h
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: bcmsdstd.h,v 13.21.2.6 2010-11-15 18:14:01 Exp $
+ * $Id: bcmsdstd.h 324819 2012-03-30 12:15:19Z $
*/
#ifndef _BCM_SD_STD_H
#define _BCM_SD_STD_H
@@ -78,6 +78,7 @@ extern void sdstd_osfree(sdioh_info_t *sd);
#define SDIOH_CMD7_EXP_STATUS 0x00001E00
#define RETRIES_LARGE 100000
+#define sdstd_os_yield(sd) do {} while (0)
#define RETRIES_SMALL 100
@@ -148,8 +149,8 @@ struct sdioh_info {
bool got_hcint; /* local interrupt flag */
uint16 last_intrstatus; /* to cache intrstatus */
int host_UHSISupported; /* whether UHSI is supported for HC. */
- int card_UHSI_voltage_Supported; /* whether UHSI is supported for
- * Card in terms of Voltage [1.8 or 3.3].
+ int card_UHSI_voltage_Supported; /* whether UHSI is supported for
+ * Card in terms of Voltage [1.8 or 3.3].
*/
int global_UHSI_Supp; /* type of UHSI support in both host and card.
* HOST_SDR_UNSUPP: capabilities not supported/matched
@@ -171,21 +172,6 @@ struct sdioh_info {
#define USE_DMA(sd) ((bool)((sd->sd_dma_mode > 0) ? TRUE : FALSE))
-/* SDIO Host Control Register DMA Mode Definitions */
-#define SDIOH_SDMA_MODE 0
-#define SDIOH_ADMA1_MODE 1
-#define SDIOH_ADMA2_MODE 2
-#define SDIOH_ADMA2_64_MODE 3
-
-#define ADMA2_ATTRIBUTE_VALID (1 << 0) /* ADMA Descriptor line valid */
-#define ADMA2_ATTRIBUTE_END (1 << 1) /* End of Descriptor */
-#define ADMA2_ATTRIBUTE_INT (1 << 2) /* Interrupt when line is done */
-#define ADMA2_ATTRIBUTE_ACT_NOP (0 << 4) /* Skip current line, go to next. */
-#define ADMA2_ATTRIBUTE_ACT_RSV (1 << 4) /* Same as NOP */
-#define ADMA1_ATTRIBUTE_ACT_SET (1 << 4) /* ADMA1 Only - set transfer length */
-#define ADMA2_ATTRIBUTE_ACT_TRAN (2 << 4) /* Transfer Data of one descriptor line. */
-#define ADMA2_ATTRIBUTE_ACT_LINK (3 << 4) /* Link Descriptor */
-
/* States for Tuning and corr data */
#define TUNING_IDLE 0
#define TUNING_START 1
@@ -194,17 +180,9 @@ struct sdioh_info {
#define DATA_TRANSFER_IDLE 0
#define DATA_TRANSFER_ONGOING 1
+#define CHECK_TUNING_PRE_DATA 1
+#define CHECK_TUNING_POST_DATA 2
-/* ADMA2 Descriptor Table Entry for 32-bit Address */
-typedef struct adma2_dscr_32b {
- uint32 len_attr;
- uint32 phys_addr;
-} adma2_dscr_32b_t;
-
-/* ADMA1 Descriptor Table Entry */
-typedef struct adma1_dscr {
- uint32 phys_addr_attr;
-} adma1_dscr_t;
/************************************************************
* Internal interfaces: per-port references into bcmsdstd.c
@@ -252,9 +230,12 @@ extern int sdstd_waitbits(sdioh_info_t *sd, uint16 norm, uint16 err, bool yield,
extern void sdstd_3_enable_retuning_int(sdioh_info_t *sd);
extern void sdstd_3_disable_retuning_int(sdioh_info_t *sd);
extern bool sdstd_3_is_retuning_int_set(sdioh_info_t *sd);
+extern void sdstd_3_check_and_do_tuning(sdioh_info_t *sd, int tuning_param);
extern bool sdstd_3_check_and_set_retuning(sdioh_info_t *sd);
extern int sdstd_3_get_tune_state(sdioh_info_t *sd);
+extern int sdstd_3_get_data_state(sdioh_info_t *sd);
extern void sdstd_3_set_tune_state(sdioh_info_t *sd, int state);
+extern void sdstd_3_set_data_state(sdioh_info_t *sd, int state);
extern uint8 sdstd_3_get_tuning_exp(sdioh_info_t *sd);
extern uint32 sdstd_3_get_uhsi_clkmode(sdioh_info_t *sd);
extern int sdstd_3_clk_tuning(sdioh_info_t *sd, uint32 sd3ClkMode);
diff --git a/drivers/net/wireless/bcmdhd/include/bcmspi.h b/drivers/net/wireless/bcmdhd/include/bcmspi.h
index 0eb2a30c9a84..34a02d00c6bd 100644
--- a/drivers/net/wireless/bcmdhd/include/bcmspi.h
+++ b/drivers/net/wireless/bcmdhd/include/bcmspi.h
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: bcmspi.h,v 13.5.112.1 2010-11-15 18:13:09 Exp $
+ * $Id: bcmspi.h 277737 2011-08-16 17:54:59Z $
*/
#ifndef _BCM_SPI_H
#define _BCM_SPI_H
diff --git a/drivers/net/wireless/bcmdhd/include/bcmutils.h b/drivers/net/wireless/bcmdhd/include/bcmutils.h
index 530036f0ba77..6849c26da837 100644
--- a/drivers/net/wireless/bcmdhd/include/bcmutils.h
+++ b/drivers/net/wireless/bcmdhd/include/bcmutils.h
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: bcmutils.h,v 13.236.2.16 2011-01-26 00:45:06 Exp $
+ * $Id: bcmutils.h 294991 2011-11-09 00:17:28Z $
*/
@@ -221,7 +221,9 @@ extern uint16 pktpool_avail(pktpool_t *pktp);
extern int pktpool_avail_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg);
extern int pktpool_empty_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg);
extern int pktpool_setmaxlen(pktpool_t *pktp, uint16 maxlen);
+extern int pktpool_setmaxlen_strict(osl_t *osh, pktpool_t *pktp, uint16 maxlen);
extern void pktpool_emptycb_disable(pktpool_t *pktp, bool disable);
+extern bool pktpool_emptycb_disabled(pktpool_t *pktp);
#define POOLPTR(pp) ((pktpool_t *)(pp))
#define pktpool_len(pp) (POOLPTR(pp)->len - 1)
@@ -330,6 +332,8 @@ extern char *bcm_ip_ntoa(struct ipv4_addr *ia, char *buf);
extern void bcm_mdelay(uint ms);
+#define NVRAM_RECLAIM_CHECK(name)
+
extern char *getvar(char *vars, const char *name);
extern int getintvar(char *vars, const char *name);
extern int getintvararray(char *vars, const char *name, int index);
@@ -534,9 +538,17 @@ extern int bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len);
& ~((boundary) - 1))
#define ISPOWEROF2(x) ((((x)-1)&(x)) == 0)
#define VALID_MASK(mask) !((mask) & ((mask) + 1))
+
#ifndef OFFSETOF
+#ifdef __ARMCC_VERSION
+
+#include <stddef.h>
+#define OFFSETOF(type, member) offsetof(type, member)
+#else
#define OFFSETOF(type, member) ((uint)(uintptr)&((type *)0)->member)
#endif
+#endif
+
#ifndef ARRAYSIZE
#define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
#endif
diff --git a/drivers/net/wireless/bcmdhd/include/bcmwifi.h b/drivers/net/wireless/bcmdhd/include/bcmwifi.h
index 45f3c0312dcc..e5207e9c4086 100644
--- a/drivers/net/wireless/bcmdhd/include/bcmwifi.h
+++ b/drivers/net/wireless/bcmdhd/include/bcmwifi.h
@@ -23,7 +23,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: bcmwifi.h,v 1.29.6.3 2010-08-03 17:47:04 Exp $
+ * $Id: bcmwifi.h 277737 2011-08-16 17:54:59Z $
*/
diff --git a/drivers/net/wireless/bcmdhd/include/dhdioctl.h b/drivers/net/wireless/bcmdhd/include/dhdioctl.h
index 9661dac2603f..175ff8545a0c 100644
--- a/drivers/net/wireless/bcmdhd/include/dhdioctl.h
+++ b/drivers/net/wireless/bcmdhd/include/dhdioctl.h
@@ -25,7 +25,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: dhdioctl.h,v 13.11.10.1 2010-12-22 23:47:26 Exp $
+ * $Id: dhdioctl.h 323572 2012-03-26 06:28:14Z $
*/
#ifndef _dhdioctl_h_
@@ -87,6 +87,8 @@ enum {
#define DHD_BTA_VAL 0x1000
#define DHD_ISCAN_VAL 0x2000
#define DHD_ARPOE_VAL 0x4000
+#define DHD_REORDER_VAL 0x8000
+#define DHD_WL_VAL 0x10000
#ifdef SDTEST
/* For pktgen iovar */
diff --git a/drivers/net/wireless/bcmdhd/include/epivers.h b/drivers/net/wireless/bcmdhd/include/epivers.h
index ae1f975bdb64..3bff73e2a6bc 100644
--- a/drivers/net/wireless/bcmdhd/include/epivers.h
+++ b/drivers/net/wireless/bcmdhd/include/epivers.h
@@ -19,11 +19,10 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: epivers.h.in,v 13.32.4.1 2010-09-17 00:39:18 $
+ * $Id: epivers.h.in 277737 2011-08-16 17:54:59Z $
*
*/
-
#ifndef _epivers_h_
#define _epivers_h_
@@ -31,19 +30,19 @@
#define EPI_MINOR_VERSION 90
-#define EPI_RC_NUMBER 125
+#define EPI_RC_NUMBER 195
-#define EPI_INCREMENTAL_NUMBER 94
+#define EPI_INCREMENTAL_NUMBER 61
#define EPI_BUILD_NUMBER 0
-#define EPI_VERSION 5, 90, 125, 94
+#define EPI_VERSION 5, 90, 195, 61
-#define EPI_VERSION_NUM 0x055a7d5e
+#define EPI_VERSION_NUM 0x055ac33d
-#define EPI_VERSION_DEV 5.90.125
+#define EPI_VERSION_DEV 5.90.195
-#define EPI_VERSION_STR "5.90.125.94"
+#define EPI_VERSION_STR "5.90.195.61"
#endif
diff --git a/drivers/net/wireless/bcmdhd/include/hndpmu.h b/drivers/net/wireless/bcmdhd/include/hndpmu.h
index 51c51b9734a2..69a834c6b7eb 100644
--- a/drivers/net/wireless/bcmdhd/include/hndpmu.h
+++ b/drivers/net/wireless/bcmdhd/include/hndpmu.h
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: hndpmu.h,v 13.35.8.5 2011-02-11 00:56:32 Exp $
+ * $Id: hndpmu.h 277737 2011-08-16 17:54:59Z $
*/
#ifndef _hndpmu_h_
diff --git a/drivers/net/wireless/bcmdhd/include/hndrte_armtrap.h b/drivers/net/wireless/bcmdhd/include/hndrte_armtrap.h
index 8b9615c35f35..7d862c4deb21 100644
--- a/drivers/net/wireless/bcmdhd/include/hndrte_armtrap.h
+++ b/drivers/net/wireless/bcmdhd/include/hndrte_armtrap.h
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: hndrte_armtrap.h,v 13.4.14.1 2011-02-05 00:04:30 Exp $
+ * $Id: hndrte_armtrap.h 277737 2011-08-16 17:54:59Z $
*/
#ifndef _hndrte_armtrap_h
diff --git a/drivers/net/wireless/bcmdhd/include/hndrte_cons.h b/drivers/net/wireless/bcmdhd/include/hndrte_cons.h
index b9ede53af701..859ddc8953a8 100644
--- a/drivers/net/wireless/bcmdhd/include/hndrte_cons.h
+++ b/drivers/net/wireless/bcmdhd/include/hndrte_cons.h
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: hndrte_cons.h,v 13.4.10.4 2011-02-05 00:08:20 Exp $
+ * $Id: hndrte_cons.h 277737 2011-08-16 17:54:59Z $
*/
#ifndef _HNDRTE_CONS_H
diff --git a/drivers/net/wireless/bcmdhd/include/hndsoc.h b/drivers/net/wireless/bcmdhd/include/hndsoc.h
index 4e26121c3881..34f927c6af80 100644
--- a/drivers/net/wireless/bcmdhd/include/hndsoc.h
+++ b/drivers/net/wireless/bcmdhd/include/hndsoc.h
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: hndsoc.h,v 13.11 2009-12-03 23:52:31 Exp $
+ * $Id: hndsoc.h 277737 2011-08-16 17:54:59Z $
*/
#ifndef _HNDSOC_H
diff --git a/drivers/net/wireless/bcmdhd/include/htsf.h b/drivers/net/wireless/bcmdhd/include/htsf.h
index 379fbbe37dbc..d875edb816c9 100644
--- a/drivers/net/wireless/bcmdhd/include/htsf.h
+++ b/drivers/net/wireless/bcmdhd/include/htsf.h
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: htsf.h,v 1.1.2.4 2011-01-21 08:27:03 Exp $
+ * $Id: htsf.h 277737 2011-08-16 17:54:59Z $
*/
#ifndef _HTSF_H_
#define _HTSF_H_
diff --git a/drivers/net/wireless/bcmdhd/include/linux_osl.h b/drivers/net/wireless/bcmdhd/include/linux_osl.h
index 1ec136eb70dc..830d351d882b 100644
--- a/drivers/net/wireless/bcmdhd/include/linux_osl.h
+++ b/drivers/net/wireless/bcmdhd/include/linux_osl.h
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: linux_osl.h,v 13.158.6.3 2010-12-22 23:47:26 Exp $
+ * $Id: linux_osl.h 301794 2011-12-08 20:41:35Z $
*/
@@ -268,7 +268,7 @@ extern int osl_error(int bcmerror);
#define PKTLIST_DUMP(osh, buf)
#define PKTDBG_TRACE(osh, pkt, bit)
#define PKTFREE(osh, skb, send) osl_pktfree((osh), (skb), (send))
-#ifdef DHD_USE_STATIC_BUF
+#ifdef CONFIG_DHD_USE_STATIC_BUF
#define PKTGET_STATIC(osh, len, send) osl_pktget_static((osh), (len))
#define PKTFREE_STATIC(osh, skb, send) osl_pktfree_static((osh), (skb), (send))
#endif
diff --git a/drivers/net/wireless/bcmdhd/include/linuxver.h b/drivers/net/wireless/bcmdhd/include/linuxver.h
index 96844db2f059..54d88ee923b2 100644
--- a/drivers/net/wireless/bcmdhd/include/linuxver.h
+++ b/drivers/net/wireless/bcmdhd/include/linuxver.h
@@ -22,7 +22,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: linuxver.h,v 13.53.2.2 2010-12-22 23:47:26 Exp $
+ * $Id: linuxver.h 312264 2012-02-02 00:49:43Z $
*/
@@ -482,7 +482,11 @@ typedef struct {
#define DBG_THR(x)
#endif
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
+#define SMP_RD_BARRIER_DEPENDS(x) smp_read_barrier_depends(x)
+#else
#define SMP_RD_BARRIER_DEPENDS(x) smp_rmb(x)
+#endif
#define PROC_START(thread_func, owner, tsk_ctl, flags) \
@@ -507,7 +511,24 @@ typedef struct {
(tsk_ctl)->thr_pid = -1; \
}
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
+#define DAEMONIZE(a) daemonize(a); \
+ allow_signal(SIGKILL); \
+ allow_signal(SIGTERM);
+#else /* Linux 2.4 (w/o preemption patch) */
+#define RAISE_RX_SOFTIRQ() \
+ cpu_raise_softirq(smp_processor_id(), NET_RX_SOFTIRQ)
+#define DAEMONIZE(a) daemonize(); \
+ do { if (a) \
+ strncpy(current->comm, a, MIN(sizeof(current->comm), (strlen(a) + 1))); \
+ } while (0);
+#endif /* LINUX_VERSION_CODE */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
+#define BLOCKABLE() (!in_atomic())
+#else
+#define BLOCKABLE() (!in_interrupt())
+#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
#define KILL_PROC(nr, sig) \
diff --git a/drivers/net/wireless/bcmdhd/include/miniopt.h b/drivers/net/wireless/bcmdhd/include/miniopt.h
index f468420f5346..77eace6252d7 100644
--- a/drivers/net/wireless/bcmdhd/include/miniopt.h
+++ b/drivers/net/wireless/bcmdhd/include/miniopt.h
@@ -20,7 +20,7 @@
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
- * $Id: miniopt.h,v 1.3 2009-01-15 00:06:54 Exp $
+ * $Id: miniopt.h 277737 2011-08-16 17:54:59Z $
*/
diff --git a/drivers/net/wireless/bcmdhd/include/msgtrace.h b/drivers/net/wireless/bcmdhd/include/msgtrace.h
index 721d42100f2a..088f1e845a43 100644
--- a/drivers/net/wireless/bcmdhd/include/msgtrace.h
+++ b/drivers/net/wireless/bcmdhd/include/msgtrace.h
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: msgtrace.h,v 1.4 2009-04-10 04:15:32 Exp $
+ * $Id: msgtrace.h 277737 2011-08-16 17:54:59Z $
*/
#ifndef _MSGTRACE_H
diff --git a/drivers/net/wireless/bcmdhd/include/osl.h b/drivers/net/wireless/bcmdhd/include/osl.h
index 80248ee7604e..b8cc2569f506 100644
--- a/drivers/net/wireless/bcmdhd/include/osl.h
+++ b/drivers/net/wireless/bcmdhd/include/osl.h
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: osl.h,v 13.44.96.1 2010-05-20 11:09:18 Exp $
+ * $Id: osl.h 277737 2011-08-16 17:54:59Z $
*/
diff --git a/drivers/net/wireless/bcmdhd/include/packed_section_end.h b/drivers/net/wireless/bcmdhd/include/packed_section_end.h
index 5d4a87678071..71f8b2e13b3b 100644
--- a/drivers/net/wireless/bcmdhd/include/packed_section_end.h
+++ b/drivers/net/wireless/bcmdhd/include/packed_section_end.h
@@ -34,7 +34,7 @@
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
- * $Id: packed_section_end.h,v 1.4 2008-12-09 23:43:22 Exp $
+ * $Id: packed_section_end.h 277737 2011-08-16 17:54:59Z $
*/
diff --git a/drivers/net/wireless/bcmdhd/include/packed_section_start.h b/drivers/net/wireless/bcmdhd/include/packed_section_start.h
index da2fed68afac..afc2ba32fd93 100644
--- a/drivers/net/wireless/bcmdhd/include/packed_section_start.h
+++ b/drivers/net/wireless/bcmdhd/include/packed_section_start.h
@@ -34,7 +34,7 @@
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
- * $Id: packed_section_start.h,v 1.4.124.1 2010-09-17 00:47:03 Exp $
+ * $Id: packed_section_start.h 277737 2011-08-16 17:54:59Z $
*/
diff --git a/drivers/net/wireless/bcmdhd/include/pcicfg.h b/drivers/net/wireless/bcmdhd/include/pcicfg.h
index fae063a72f18..66199431fb92 100644
--- a/drivers/net/wireless/bcmdhd/include/pcicfg.h
+++ b/drivers/net/wireless/bcmdhd/include/pcicfg.h
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: pcicfg.h,v 1.50 2009-12-07 21:56:06 Exp $
+ * $Id: pcicfg.h 277737 2011-08-16 17:54:59Z $
*/
@@ -39,6 +39,19 @@
#define PCI_INT_MASK 0x94
#define PCIE_EXTCFG_OFFSET 0x100
+#define PCI_SPROM_CONTROL 0x88
+#define PCI_BAR1_CONTROL 0x8c
+#define PCI_TO_SB_MB 0x98
+#define PCI_BACKPLANE_ADDR 0xa0
+#define PCI_BACKPLANE_DATA 0xa4
+#define PCI_CLK_CTL_ST 0xa8
+#define PCI_BAR0_WIN2 0xac
+#define PCI_GPIO_IN 0xb0
+#define PCI_GPIO_OUT 0xb4
+#define PCI_GPIO_OUTEN 0xb8
+
+#define PCI_BAR0_SHADOW_OFFSET (2 * 1024)
+#define PCI_BAR0_SPROM_OFFSET (4 * 1024)
#define PCI_BAR0_PCIREGS_OFFSET (6 * 1024)
#define PCI_BAR0_PCISBR_OFFSET (4 * 1024)
@@ -49,4 +62,17 @@
#define PCI_16KB0_CCREGS_OFFSET (12 * 1024)
#define PCI_16KBB0_WINSZ (16 * 1024)
+
+#define PCI_16KB0_WIN2_OFFSET (4 * 1024)
+
+
+
+#define SPROM_SZ_MSK 0x02
+#define SPROM_LOCKED 0x08
+#define SPROM_BLANK 0x04
+#define SPROM_WRITEEN 0x10
+#define SPROM_BOOTROM_WE 0x20
+#define SPROM_BACKPLANE_EN 0x40
+#define SPROM_OTPIN_USE 0x80
+
#endif
diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.11.h b/drivers/net/wireless/bcmdhd/include/proto/802.11.h
index 2342cb383147..fd69aac41309 100644
--- a/drivers/net/wireless/bcmdhd/include/proto/802.11.h
+++ b/drivers/net/wireless/bcmdhd/include/proto/802.11.h
@@ -21,7 +21,7 @@
*
* Fundamental types and constants relating to 802.11
*
- * $Id: 802.11.h,v 9.260.2.6 2010-12-15 21:41:14 Exp $
+ * $Id: 802.11.h 304058 2011-12-21 00:39:12Z $
*/
@@ -429,10 +429,26 @@ typedef struct dot11_obss_chanlist dot11_obss_chanlist_t;
BWL_PRE_PACKED_STRUCT struct dot11_extcap_ie {
uint8 id;
uint8 len;
- uint8 cap;
+ uint8 cap[1];
} BWL_POST_PACKED_STRUCT;
typedef struct dot11_extcap_ie dot11_extcap_ie_t;
#define DOT11_EXTCAP_LEN 1
+#define DOT11_EXTCAP_LEN_TDLS 5
+
+BWL_PRE_PACKED_STRUCT struct dot11_extcap {
+ uint8 extcap[DOT11_EXTCAP_LEN_TDLS];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_extcap dot11_extcap_t;
+
+
+#define TDLS_CAP_TDLS 37
+#define TDLS_CAP_PU_BUFFER_STA 28
+#define TDLS_CAP_PEER_PSM 20
+#define TDLS_CAP_CH_SW 30
+#define TDLS_CAP_PROH 38
+#define TDLS_CAP_CH_SW_PROH 39
+
+#define TDLS_CAP_MAX_BIT 39
@@ -545,6 +561,9 @@ typedef struct dot11_ibss_dfs dot11_ibss_dfs_t;
#define WME_SUBTYPE_IE 0
#define WME_SUBTYPE_PARAM_IE 1
#define WME_SUBTYPE_TSPEC 2
+#define WME_VERSION_LEN 1
+#define WME_PARAMETER_IE_LEN 24
+
#define AC_BE 0
@@ -709,6 +728,15 @@ BWL_PRE_PACKED_STRUCT struct dot11_management_notification {
#define DOT11_MGMT_NOTIFICATION_LEN 4
+BWL_PRE_PACKED_STRUCT struct ti_ie {
+ uint8 ti_type;
+ uint32 ti_val;
+} BWL_POST_PACKED_STRUCT;
+typedef struct ti_ie ti_ie_t;
+#define TI_TYPE_REASSOC_DEADLINE 1
+#define TI_TYPE_KEY_LIFETIME 2
+
+
#define WME_ADDTS_REQUEST 0
#define WME_ADDTS_RESPONSE 1
#define WME_DELTS_REQUEST 2
@@ -724,8 +752,7 @@ BWL_PRE_PACKED_STRUCT struct dot11_management_notification {
#define DOT11_OPEN_SYSTEM 0
#define DOT11_SHARED_KEY 1
-#define DOT11_OPEN_SHARED 2
-#define DOT11_FAST_BSS 3
+#define DOT11_FAST_BSS 2
#define DOT11_CHALLENGE_LEN 128
@@ -926,9 +953,18 @@ BWL_PRE_PACKED_STRUCT struct dot11_management_notification {
#define DOT11_RC_MAX 23
+#define DOT11_RC_TDLS_PEER_UNREACH 25
+#define DOT11_RC_TDLS_DOWN_UNSPECIFIED 26
+
#define DOT11_SC_SUCCESS 0
#define DOT11_SC_FAILURE 1
+#define DOT11_SC_TDLS_WAKEUP_SCH_ALT 2
+
+#define DOT11_SC_TDLS_WAKEUP_SCH_REJ 3
+#define DOT11_SC_TDLS_SEC_DISABLED 5
+#define DOT11_SC_LIFETIME_REJ 6
+#define DOT11_SC_NOT_SAME_BSS 7
#define DOT11_SC_CAP_MISMATCH 10
#define DOT11_SC_REASSOC_FAIL 11
#define DOT11_SC_ASSOC_FAIL 12
@@ -947,13 +983,22 @@ BWL_PRE_PACKED_STRUCT struct dot11_management_notification {
#define DOT11_SC_ASSOC_SHORTSLOT_REQUIRED 25
#define DOT11_SC_ASSOC_ERPBCC_REQUIRED 26
#define DOT11_SC_ASSOC_DSSOFDM_REQUIRED 27
-
-#define DOT11_SC_DECLINED 37
-#define DOT11_SC_INVALID_PARAMS 38
-#define DOT11_SC_INVALID_AKMP 43
-#define DOT11_SC_INVALID_MDID 54
-#define DOT11_SC_INVALID_FTIE 55
-
+#define DOT11_SC_ASSOC_R0KH_UNREACHABLE 28
+#define DOT11_SC_ASSOC_TRY_LATER 30
+#define DOT11_SC_ASSOC_MFP_VIOLATION 31
+
+#define DOT11_SC_DECLINED 37
+#define DOT11_SC_INVALID_PARAMS 38
+#define DOT11_SC_INVALID_PAIRWISE_CIPHER 42
+#define DOT11_SC_INVALID_AKMP 43
+#define DOT11_SC_INVALID_RSNIE_CAP 45
+#define DOT11_SC_INVALID_PMKID 53
+#define DOT11_SC_INVALID_MDID 54
+#define DOT11_SC_INVALID_FTIE 55
+
+#define DOT11_SC_UNEXP_MSG 70
+#define DOT11_SC_INVALID_SNONCE 71
+#define DOT11_SC_INVALID_RSNIE 72
#define DOT11_MNG_DS_PARAM_LEN 1
#define DOT11_MNG_IBSS_PARAM_LEN 2
@@ -1008,6 +1053,7 @@ BWL_PRE_PACKED_STRUCT struct dot11_management_notification {
#define DOT11_MNG_MDIE_ID 54
#define DOT11_MNG_FTIE_ID 55
#define DOT11_MNG_FT_TI_ID 56
+#define DOT11_MNG_RDE_ID 57
#define DOT11_MNG_REGCLASS_ID 59
#define DOT11_MNG_EXT_CSA_ID 60
#define DOT11_MNG_HT_ADD 61
@@ -1018,7 +1064,13 @@ BWL_PRE_PACKED_STRUCT struct dot11_management_notification {
#define DOT11_MNG_HT_BSS_COEXINFO_ID 72
#define DOT11_MNG_HT_BSS_CHANNEL_REPORT_ID 73
#define DOT11_MNG_HT_OBSS_ID 74
-#define DOT11_MNG_EXT_CAP 127
+#define DOT11_MNG_CHANNEL_USAGE 97
+#define DOT11_MNG_LINK_IDENTIFIER_ID 101
+#define DOT11_MNG_WAKEUP_SCHEDULE_ID 102
+#define DOT11_MNG_CHANNEL_SWITCH_TIMING_ID 104
+#define DOT11_MNG_PTI_CONTROL_ID 105
+#define DOT11_MNG_PU_BUFFER_STATUS_ID 106
+#define DOT11_MNG_EXT_CAP_ID 127
#define DOT11_MNG_WPA_ID 221
#define DOT11_MNG_PROPR_ID 221
@@ -1070,8 +1122,14 @@ BWL_PRE_PACKED_STRUCT struct dot11_management_notification {
#define DOT11_ACTION_CAT_RRM 5
#define DOT11_ACTION_CAT_FBT 6
#define DOT11_ACTION_CAT_HT 7
+#if defined(MFP) || defined(WLFBT) || defined(WLWNM)
+#define DOT11_ACTION_CAT_SA_QUERY 8
+#define DOT11_ACTION_CAT_PDPA 9
#define DOT11_ACTION_CAT_BSSMGMT 10
#define DOT11_ACTION_NOTIFICATION 17
+#define DOT11_ACTION_CAT_VSP 126
+#endif
+#define DOT11_ACTION_NOTIFICATION 17
#define DOT11_ACTION_CAT_VS 127
@@ -1107,6 +1165,121 @@ BWL_PRE_PACKED_STRUCT struct dot11_management_notification {
#define DOT11_ADDBA_POLICY_DELAYED 0
#define DOT11_ADDBA_POLICY_IMMEDIATE 1
+
+#define DOT11_FT_ACTION_FT_RESERVED 0
+#define DOT11_FT_ACTION_FT_REQ 1
+#define DOT11_FT_ACTION_FT_RES 2
+#define DOT11_FT_ACTION_FT_CON 3
+#define DOT11_FT_ACTION_FT_ACK 4
+
+
+
+#define DOT11_WNM_ACTION_EVENT_REQ 0
+#define DOT11_WNM_ACTION_EVENT_REP 1
+#define DOT11_WNM_ACTION_DIAG_REQ 2
+#define DOT11_WNM_ACTION_DIAG_REP 3
+#define DOT11_WNM_ACTION_LOC_CFG_REQ 4
+#define DOT11_WNM_ACTION_LOC_RFG_RESP 5
+#define DOT11_WNM_ACTION_BSS_TRANS_QURY 6
+#define DOT11_WNM_ACTION_BSS_TRANS_REQ 7
+#define DOT11_WNM_ACTION_BSS_TRANS_RESP 8
+#define DOT11_WNM_ACTION_FMS_REQ 9
+#define DOT11_WNM_ACTION_FMS_RESP 10
+#define DOT11_WNM_ACTION_COL_INTRFRNCE_REQ 11
+#define DOT11_WNM_ACTION_COL_INTRFRNCE_REP 12
+#define DOT11_WNM_ACTION_TFS_REQ 13
+#define DOT11_WNM_ACTION_TFS_RESP 14
+#define DOT11_WNM_ACTION_TFS_NOTIFY 15
+#define DOT11_WNM_ACTION_WNM_SLEEP_REQ 16
+#define DOT11_WNM_ACTION_WNM_SLEEP_RESP 17
+#define DOT11_WNM_ACTION_TIM_BCAST_REQ 18
+#define DOT11_WNM_ACTION_TIM_BCAST_RESP 19
+#define DOT11_WNM_ACTION_QOS_TRFC_CAP_UPD 20
+#define DOT11_WNM_ACTION_CHAN_USAGE_REQ 21
+#define DOT11_WNM_ACTION_CHAN_USAGE_RESP 22
+#define DOT11_WNM_ACTION_DMS_REQ 23
+#define DOT11_WNM_ACTION_DMS_RESP 24
+#define DOT11_WNM_ACTION_TMNG_MEASUR_REQ 25
+#define DOT11_WNM_ACTION_NOTFCTN_REQ 26
+#define DOT11_WNM_ACTION_NOTFCTN_RES 27
+
+
+
+BWL_PRE_PACKED_STRUCT struct dot11_bss_trans_query {
+ uint8 category;
+ uint8 action;
+ uint8 token;
+ uint8 reason;
+ uint8 data[1];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_bss_trans_query dot11_bss_trans_query_t;
+#define DOT11_BSS_TRANS_QUERY_LEN 4
+
+
+BWL_PRE_PACKED_STRUCT struct dot11_bss_trans_req {
+ uint8 category;
+ uint8 action;
+ uint8 token;
+ uint8 reqmode;
+ uint16 disassoc_tmr;
+ uint8 validity_intrvl;
+ uint8 data[1];
+
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_bss_trans_req dot11_bss_trans_req_t;
+#define DOT11_BSS_TRANS_REQ_LEN 7
+
+#define DOT11_BSS_TERM_DUR_LEN 12
+
+
+
+#define DOT11_BSS_TRNS_REQMODE_PREF_LIST_INCL 0x01
+#define DOT11_BSS_TRNS_REQMODE_ABRIDGED 0x02
+#define DOT11_BSS_TRNS_REQMODE_DISASSOC_IMMINENT 0x04
+#define DOT11_BSS_TRNS_REQMODE_BSS_TERM_INCL 0x08
+#define DOT11_BSS_TRNS_REQMODE_ESS_DISASSOC_IMNT 0x10
+
+
+
+BWL_PRE_PACKED_STRUCT struct dot11_bss_trans_res {
+ uint8 category;
+ uint8 action;
+ uint8 token;
+ uint8 status;
+ uint8 term_delay;
+ uint8 data[1];
+
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_bss_trans_res dot11_bss_trans_res_t;
+#define DOT11_BSS_TRANS_RES_LEN 5
+
+
+#define DOT11_BSS_TRNS_RES_STATUS_ACCEPT 0
+#define DOT11_BSS_TRNS_RES_STATUS_REJECT 1
+#define DOT11_BSS_TRNS_RES_STATUS_REJ_INSUFF_BCN 2
+#define DOT11_BSS_TRNS_RES_STATUS_REJ_INSUFF_CAP 3
+#define DOT11_BSS_TRNS_RES_STATUS_REJ_TERM_UNDESIRED 4
+#define DOT11_BSS_TRNS_RES_STATUS_REJ_TERM_DELAY_REQ 5
+#define DOT11_BSS_TRNS_RES_STATUS_REJ_BSS_LIST_PROVIDED 6
+#define DOT11_BSS_TRNS_RES_STATUS_REJ_NO_SUITABLE_BSS 7
+#define DOT11_BSS_TRNS_RES_STATUS_REJ_LEAVING_ESS 8
+
+
+
+#define DOT11_NBR_RPRT_BSSID_INFO_REACHABILTY 0x0003
+#define DOT11_NBR_RPRT_BSSID_INFO_SEC 0x0004
+#define DOT11_NBR_RPRT_BSSID_INFO_KEY_SCOPE 0x0008
+#define DOT11_NBR_RPRT_BSSID_INFO_CAP 0x03f0
+
+#define DOT11_NBR_RPRT_BSSID_INFO_CAP_SPEC_MGMT 0x0010
+#define DOT11_NBR_RPRT_BSSID_INFO_CAP_QOS 0x0020
+#define DOT11_NBR_RPRT_BSSID_INFO_CAP_APSD 0x0040
+#define DOT11_NBR_RPRT_BSSID_INFO_CAP_RDIO_MSMT 0x0080
+#define DOT11_NBR_RPRT_BSSID_INFO_CAP_DEL_BA 0x0100
+#define DOT11_NBR_RPRT_BSSID_INFO_CAP_IMM_BA 0x0200
+
+
+#define DOT11_NBR_RPRT_SUBELEM_BSS_CANDDT_PREF_ID 3
BWL_PRE_PACKED_STRUCT struct dot11_addba_req {
uint8 category;
uint8 action;
@@ -1145,6 +1318,48 @@ typedef struct dot11_delba dot11_delba_t;
#define DOT11_DELBA_LEN 6
+#define SA_QUERY_REQUEST 0
+#define SA_QUERY_RESPONSE 1
+
+
+
+
+BWL_PRE_PACKED_STRUCT struct dot11_ft_req {
+ uint8 category;
+ uint8 action;
+ uint8 sta_addr[ETHER_ADDR_LEN];
+ uint8 tgt_ap_addr[ETHER_ADDR_LEN];
+ uint8 data[1];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_ft_req dot11_ft_req_t;
+#define DOT11_FT_REQ_FIXED_LEN 14
+
+
+BWL_PRE_PACKED_STRUCT struct dot11_ft_res {
+ uint8 category;
+ uint8 action;
+ uint8 sta_addr[ETHER_ADDR_LEN];
+ uint8 tgt_ap_addr[ETHER_ADDR_LEN];
+ uint16 status;
+ uint8 data[1];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_ft_res dot11_ft_res_t;
+#define DOT11_FT_RES_FIXED_LEN 16
+
+
+BWL_PRE_PACKED_STRUCT struct dot11_rde_ie {
+ uint8 id;
+ uint8 length;
+ uint8 rde_id;
+ uint8 rd_count;
+ uint16 status;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_rde_ie dot11_rde_ie_t;
+
+
+#define DOT11_MNG_RDE_IE_LEN sizeof(dot11_rde_ie_t)
+
+
@@ -1166,6 +1381,28 @@ typedef struct dot11_rrm_cap_ie dot11_rrm_cap_ie_t;
#define DOT11_RRM_CAP_AP_CHANREP 16
+
+#define DOT11_EXT_CAP_LEN 4
+BWL_PRE_PACKED_STRUCT struct dot11_ext_cap_ie {
+ uint8 cap[DOT11_EXT_CAP_LEN];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_ext_cap_ie dot11_ext_cap_ie_t;
+
+
+#define DOT11_EXT_CAP_BSS_TRANSITION_MGMT 19
+
+
+#define DOT11_OP_CLASS_NONE 255
+
+BWL_PRE_PACKED_STRUCT struct do11_ap_chrep {
+ uint8 id;
+ uint8 len;
+ uint8 reg;
+ uint8 chanlist[1];
+} BWL_POST_PACKED_STRUCT;
+typedef struct do11_ap_chrep dot11_ap_chrep_t;
+
+
#define DOT11_RM_ACTION_RM_REQ 0
#define DOT11_RM_ACTION_RM_REP 1
#define DOT11_RM_ACTION_LM_REQ 2
@@ -1255,7 +1492,7 @@ typedef struct dot11_rmrep_bcn dot11_rmrep_bcn_t;
#define DOT11_RMREQ_BCN_REPINFO_ID 1
#define DOT11_RMREQ_BCN_REPDET_ID 2
#define DOT11_RMREQ_BCN_REQUEST_ID 10
-#define DOT11_RMREQ_BCN_APCHREP_ID 51
+#define DOT11_RMREQ_BCN_APCHREP_ID DOT11_MNG_AP_CHREP_ID
#define DOT11_RMREQ_BCN_REPDET_FIXED 0
@@ -1272,6 +1509,7 @@ BWL_PRE_PACKED_STRUCT struct dot11_rmrep_nbr {
uint8 reg;
uint8 channel;
uint8 phytype;
+ uchar sub_elements[1];
} BWL_POST_PACKED_STRUCT;
typedef struct dot11_rmrep_nbr dot11_rmrep_nbr_t;
#define DOT11_RMREP_NBR_LEN 13
@@ -1660,6 +1898,9 @@ typedef struct dot11_obss_ie dot11_obss_ie_t;
#define RSN_AKM_PSK 2
#define RSN_AKM_FBT_1X 3
#define RSN_AKM_FBT_PSK 4
+#define RSN_AKM_MFP_1X 5
+#define RSN_AKM_MFP_PSK 6
+#define RSN_AKM_TPK 7
#define DOT11_MAX_DEFAULT_KEYS 4
@@ -1724,6 +1965,66 @@ BWL_PRE_PACKED_STRUCT struct dot11_gtk_ie {
} BWL_POST_PACKED_STRUCT;
typedef struct dot11_gtk_ie dot11_gtk_ie_t;
+#define BSSID_INVALID "\x00\x00\x00\x00\x00\x00"
+#define BSSID_BROADCAST "\xFF\xFF\xFF\xFF\xFF\xFF"
+
+
+
+BWL_PRE_PACKED_STRUCT struct link_id_ie {
+ uint8 id;
+ uint8 len;
+ struct ether_addr bssid;
+ struct ether_addr tdls_init_mac;
+ struct ether_addr tdls_resp_mac;
+} BWL_POST_PACKED_STRUCT;
+typedef struct link_id_ie link_id_ie_t;
+#define TDLS_LINK_ID_IE_LEN 18
+
+
+BWL_PRE_PACKED_STRUCT struct wakeup_sch_ie {
+ uint8 id;
+ uint8 len;
+ uint32 offset;
+ uint32 interval;
+ uint32 awake_win_slots;
+ uint32 max_wake_win;
+ uint16 idle_cnt;
+} BWL_POST_PACKED_STRUCT;
+typedef struct wakeup_sch_ie wakeup_sch_ie_t;
+#define TDLS_WAKEUP_SCH_IE_LEN 18
+
+
+BWL_PRE_PACKED_STRUCT struct channel_switch_timing_ie {
+ uint8 id;
+ uint8 len;
+ uint16 switch_time;
+ uint16 switch_timeout;
+} BWL_POST_PACKED_STRUCT;
+typedef struct channel_switch_timing_ie channel_switch_timing_ie_t;
+#define TDLS_CHANNEL_SWITCH_TIMING_IE_LEN 4
+
+
+BWL_PRE_PACKED_STRUCT struct pti_control_ie {
+ uint8 id;
+ uint8 len;
+ uint8 tid;
+ uint16 seq_control;
+} BWL_POST_PACKED_STRUCT;
+typedef struct pti_control_ie pti_control_ie_t;
+#define TDLS_PTI_CONTROL_IE_LEN 3
+
+
+BWL_PRE_PACKED_STRUCT struct pu_buffer_status_ie {
+ uint8 id;
+ uint8 len;
+ uint8 status;
+} BWL_POST_PACKED_STRUCT;
+typedef struct pu_buffer_status_ie pu_buffer_status_ie_t;
+#define TDLS_PU_BUFFER_STATUS_IE_LEN 1
+#define TDLS_PU_BUFFER_STATUS_AC_BK 1
+#define TDLS_PU_BUFFER_STATUS_AC_BE 2
+#define TDLS_PU_BUFFER_STATUS_AC_VI 4
+#define TDLS_PU_BUFFER_STATUS_AC_VO 8
#include <packed_section_end.h>
diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.11_bta.h b/drivers/net/wireless/bcmdhd/include/proto/802.11_bta.h
index 4ccfab02056b..cbdd05e624bc 100644
--- a/drivers/net/wireless/bcmdhd/include/proto/802.11_bta.h
+++ b/drivers/net/wireless/bcmdhd/include/proto/802.11_bta.h
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: 802.11_bta.h,v 9.2 2008-10-28 23:27:13 Exp $
+ * $Id: 802.11_bta.h 277737 2011-08-16 17:54:59Z $
*/
#ifndef _802_11_BTA_H_
diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.11e.h b/drivers/net/wireless/bcmdhd/include/proto/802.11e.h
index ce8ad083f286..0e070a475b64 100644
--- a/drivers/net/wireless/bcmdhd/include/proto/802.11e.h
+++ b/drivers/net/wireless/bcmdhd/include/proto/802.11e.h
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: 802.11e.h,v 1.6 2008-12-01 22:55:11 Exp $
+ * $Id: 802.11e.h 277737 2011-08-16 17:54:59Z $
*/
#ifndef _802_11e_H_
diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.1d.h b/drivers/net/wireless/bcmdhd/include/proto/802.1d.h
index cf206250246f..c7e07bd5e7c3 100644
--- a/drivers/net/wireless/bcmdhd/include/proto/802.1d.h
+++ b/drivers/net/wireless/bcmdhd/include/proto/802.1d.h
@@ -21,7 +21,7 @@
*
* Fundamental types and constants relating to 802.1D
*
- * $Id: 802.1d.h,v 9.3 2007-04-10 21:33:06 Exp $
+ * $Id: 802.1d.h 277737 2011-08-16 17:54:59Z $
*/
diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmeth.h b/drivers/net/wireless/bcmdhd/include/proto/bcmeth.h
index 46fa4c9f89e8..0f75d3c8f1d6 100644
--- a/drivers/net/wireless/bcmdhd/include/proto/bcmeth.h
+++ b/drivers/net/wireless/bcmdhd/include/proto/bcmeth.h
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: bcmeth.h,v 9.12 2009-12-29 19:57:18 Exp $
+ * $Id: bcmeth.h 277737 2011-08-16 17:54:59Z $
*/
diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h b/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h
index 30ec848c40ae..e8c2387dd10b 100644
--- a/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h
+++ b/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h
@@ -23,7 +23,7 @@
*
* Dependencies: proto/bcmeth.h
*
- * $Id: bcmevent.h,v 9.64.2.9 2011-02-01 06:24:21 Exp $
+ * $Id: bcmevent.h 288077 2011-10-06 00:08:47Z $
*
*/
@@ -182,7 +182,10 @@ typedef BWL_PRE_PACKED_STRUCT struct bcm_event {
#define WLC_E_PFN_SCAN_NONE 82
#define WLC_E_PFN_SCAN_ALLGONE 83
#define WLC_E_GTK_PLUMBED 84
-#define WLC_E_LAST 85
+#define WLC_E_ASSOC_REQ_IE 85
+#define WLC_E_ASSOC_RESP_IE 86
+#define WLC_E_LAST 87
+
typedef struct {
@@ -226,6 +229,8 @@ extern const int bcmevent_names_size;
#define WLC_E_REASON_TSPEC_REJECTED 7
#define WLC_E_REASON_BETTER_AP 8
+#define WLC_E_REASON_REQUESTED_ROAM 11
+
#define WLC_E_PRUNE_ENCR_MISMATCH 1
#define WLC_E_PRUNE_BCAST_BSSID 2
diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmip.h b/drivers/net/wireless/bcmdhd/include/proto/bcmip.h
index 8a8f3146d56b..55eff247c492 100644
--- a/drivers/net/wireless/bcmdhd/include/proto/bcmip.h
+++ b/drivers/net/wireless/bcmdhd/include/proto/bcmip.h
@@ -21,7 +21,7 @@
*
* Fundamental constants relating to IP Protocol
*
- * $Id: bcmip.h,v 9.19 2009-11-10 20:08:33 Exp $
+ * $Id: bcmip.h 277737 2011-08-16 17:54:59Z $
*/
diff --git a/drivers/net/wireless/bcmdhd/include/proto/bt_amp_hci.h b/drivers/net/wireless/bcmdhd/include/proto/bt_amp_hci.h
index 89c118179159..91ab4fe538f2 100644
--- a/drivers/net/wireless/bcmdhd/include/proto/bt_amp_hci.h
+++ b/drivers/net/wireless/bcmdhd/include/proto/bt_amp_hci.h
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: bt_amp_hci.h,v 9.14.8.2 2010-09-10 18:37:47 Exp $
+ * $Id: bt_amp_hci.h 277737 2011-08-16 17:54:59Z $
*/
#ifndef _bt_amp_hci_h
diff --git a/drivers/net/wireless/bcmdhd/include/proto/eapol.h b/drivers/net/wireless/bcmdhd/include/proto/eapol.h
index 5781d1312e35..92634c1221a6 100644
--- a/drivers/net/wireless/bcmdhd/include/proto/eapol.h
+++ b/drivers/net/wireless/bcmdhd/include/proto/eapol.h
@@ -7,7 +7,7 @@
*
* Copyright (C) 2002 Broadcom Corporation
*
- * $Id: eapol.h,v 9.23.86.1 2010-09-02 18:09:39 Exp $
+ * $Id: eapol.h 277737 2011-08-16 17:54:59Z $
*/
#ifndef _eapol_h_
diff --git a/drivers/net/wireless/bcmdhd/include/proto/ethernet.h b/drivers/net/wireless/bcmdhd/include/proto/ethernet.h
index 6a6dd14c1bbb..20865dc5a231 100644
--- a/drivers/net/wireless/bcmdhd/include/proto/ethernet.h
+++ b/drivers/net/wireless/bcmdhd/include/proto/ethernet.h
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: ethernet.h,v 9.56 2009-10-15 22:54:58 Exp $
+ * $Id: ethernet.h 285437 2011-09-21 22:16:56Z $
*/
@@ -69,6 +69,7 @@
#define ETHER_TYPE_802_1X 0x888e
#define ETHER_TYPE_802_1X_PREAUTH 0x88c7
#define ETHER_TYPE_WAI 0x88b4
+#define ETHER_TYPE_89_0D 0x890d
diff --git a/drivers/net/wireless/bcmdhd/include/proto/p2p.h b/drivers/net/wireless/bcmdhd/include/proto/p2p.h
index 4a0c9d1ddc37..d2bf3f20688c 100644
--- a/drivers/net/wireless/bcmdhd/include/proto/p2p.h
+++ b/drivers/net/wireless/bcmdhd/include/proto/p2p.h
@@ -21,7 +21,7 @@
*
* Fundamental types and constants relating to WFA P2P (aka WiFi Direct)
*
- * $Id: p2p.h,v 9.17.2.4 2010-12-15 21:41:21 Exp $
+ * $Id: p2p.h 277737 2011-08-16 17:54:59Z $
*/
#ifndef _P2P_H_
diff --git a/drivers/net/wireless/bcmdhd/include/proto/sdspi.h b/drivers/net/wireless/bcmdhd/include/proto/sdspi.h
index 7fe4fbce310e..7353ff0d7c73 100644
--- a/drivers/net/wireless/bcmdhd/include/proto/sdspi.h
+++ b/drivers/net/wireless/bcmdhd/include/proto/sdspi.h
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: sdspi.h,v 9.2.120.1 2010-11-15 17:56:25 Exp $
+ * $Id: sdspi.h 277737 2011-08-16 17:54:59Z $
*/
#ifndef _SD_SPI_H
diff --git a/drivers/net/wireless/bcmdhd/include/proto/vlan.h b/drivers/net/wireless/bcmdhd/include/proto/vlan.h
index 07fa7e499c23..27f005537604 100644
--- a/drivers/net/wireless/bcmdhd/include/proto/vlan.h
+++ b/drivers/net/wireless/bcmdhd/include/proto/vlan.h
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: vlan.h,v 9.7 2009-03-13 01:11:50 Exp $
+ * $Id: vlan.h 277737 2011-08-16 17:54:59Z $
*/
diff --git a/drivers/net/wireless/bcmdhd/include/proto/wpa.h b/drivers/net/wireless/bcmdhd/include/proto/wpa.h
index 1ff06dc79423..7361cbf20b06 100644
--- a/drivers/net/wireless/bcmdhd/include/proto/wpa.h
+++ b/drivers/net/wireless/bcmdhd/include/proto/wpa.h
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: wpa.h,v 1.19 2009-07-13 08:29:58 Exp $
+ * $Id: wpa.h 285437 2011-09-21 22:16:56Z $
*/
@@ -114,6 +114,8 @@ typedef BWL_PRE_PACKED_STRUCT struct
#define WPA_CIPHER_AES_OCB 3
#define WPA_CIPHER_AES_CCM 4
#define WPA_CIPHER_WEP_104 5
+#define WPA_CIPHER_BIP 6
+#define WPA_CIPHER_TPK 7
#define IS_WPA_CIPHER(cipher) ((cipher) == WPA_CIPHER_NONE || \
@@ -121,7 +123,9 @@ typedef BWL_PRE_PACKED_STRUCT struct
(cipher) == WPA_CIPHER_WEP_104 || \
(cipher) == WPA_CIPHER_TKIP || \
(cipher) == WPA_CIPHER_AES_OCB || \
- (cipher) == WPA_CIPHER_AES_CCM)
+ (cipher) == WPA_CIPHER_AES_CCM || \
+ (cipher) == WPA_CIPHER_TPK)
+
#define WPA_TKIP_CM_DETECT 60
@@ -149,7 +153,11 @@ typedef BWL_PRE_PACKED_STRUCT struct
#define WPA_CAP_REPLAY_CNTR_MASK RSN_CAP_PTK_REPLAY_CNTR_MASK
+#define WPA_CAP_PEER_KEY_ENABLE (0x1 << 1)
+
+
#define WPA_CAP_LEN RSN_CAP_LEN
+#define WPA_PMKID_CNT_LEN 2
#define WPA_CAP_WPA2_PREAUTH RSN_CAP_PREAUTH
diff --git a/drivers/net/wireless/bcmdhd/include/sbchipc.h b/drivers/net/wireless/bcmdhd/include/sbchipc.h
index cbd37490f1cb..8f757509b95d 100644
--- a/drivers/net/wireless/bcmdhd/include/sbchipc.h
+++ b/drivers/net/wireless/bcmdhd/include/sbchipc.h
@@ -5,7 +5,7 @@
* JTAG, 0/1/2 UARTs, clock frequency control, a watchdog interrupt timer,
* GPIO interface, extbus, and support for serial and parallel flashes.
*
- * $Id: sbchipc.h,v 13.169.2.14 2011-02-10 23:43:55 Exp $
+ * $Id: sbchipc.h 311371 2012-01-28 05:47:25Z $
*
* Copyright (C) 1999-2011, Broadcom Corporation
*
@@ -41,6 +41,50 @@
#define PAD _XSTR(__LINE__)
#endif
+typedef struct eci_prerev35 {
+ uint32 eci_output;
+ uint32 eci_control;
+ uint32 eci_inputlo;
+ uint32 eci_inputmi;
+ uint32 eci_inputhi;
+ uint32 eci_inputintpolaritylo;
+ uint32 eci_inputintpolaritymi;
+ uint32 eci_inputintpolarityhi;
+ uint32 eci_intmasklo;
+ uint32 eci_intmaskmi;
+ uint32 eci_intmaskhi;
+ uint32 eci_eventlo;
+ uint32 eci_eventmi;
+ uint32 eci_eventhi;
+ uint32 eci_eventmasklo;
+ uint32 eci_eventmaskmi;
+ uint32 eci_eventmaskhi;
+ uint32 PAD[3];
+} eci_prerev35_t;
+
+typedef struct eci_rev35 {
+ uint32 eci_outputlo;
+ uint32 eci_outputhi;
+ uint32 eci_controllo;
+ uint32 eci_controlhi;
+ uint32 eci_inputlo;
+ uint32 eci_inputhi;
+ uint32 eci_inputintpolaritylo;
+ uint32 eci_inputintpolarityhi;
+ uint32 eci_intmasklo;
+ uint32 eci_intmaskhi;
+ uint32 eci_eventlo;
+ uint32 eci_eventhi;
+ uint32 eci_eventmasklo;
+ uint32 eci_eventmaskhi;
+ uint32 eci_auxtx;
+ uint32 eci_auxrx;
+ uint32 eci_datatag;
+ uint32 eci_uartescvalue;
+ uint32 eci_autobaudctr;
+ uint32 eci_uartfifolevel;
+} eci_rev35_t;
+
typedef volatile struct {
uint32 chipid;
uint32 capabilities;
@@ -153,10 +197,26 @@ typedef volatile struct {
uint32 prog_waitcount;
uint32 flash_config;
uint32 flash_waitcount;
- uint32 PAD[4];
- uint32 PAD[40];
+ uint32 SECI_config;
+ uint32 SECI_status;
+ uint32 SECI_statusmask;
+ uint32 SECI_rxnibchanged;
+
+ uint32 PAD[20];
+ uint32 sromcontrol;
+ uint32 sromaddress;
+ uint32 sromdata;
+ uint32 PAD[9];
+ uint32 seci_uart_data;
+ uint32 seci_uart_bauddiv;
+ uint32 seci_uart_fcr;
+ uint32 seci_uart_lcr;
+ uint32 seci_uart_mcr;
+ uint32 seci_uart_lsr;
+ uint32 seci_uart_msr;
+ uint32 seci_uart_baudadj;
uint32 clk_ctl_st;
uint32 hw_war;
@@ -1332,9 +1392,27 @@ typedef volatile struct {
#define CST43237_BOOT_FROM_INVALID 3
+#define RES43239_CBUCK_LPOM 0
+#define RES43239_CBUCK_BURST 1
+#define RES43239_CBUCK_LP_PWM 2
+#define RES43239_CBUCK_PWM 3
+#define RES43239_CLDO_PU 4
+#define RES43239_DIS_INT_RESET_PD 5
+#define RES43239_ILP_REQUEST 6
+#define RES43239_LNLDO_PU 7
+#define RES43239_LDO3P3_PU 8
#define RES43239_OTP_PU 9
+#define RES43239_XTAL_PU 10
+#define RES43239_ALP_AVAIL 11
+#define RES43239_RADIO_PU 12
#define RES43239_MACPHY_CLKAVAIL 23
#define RES43239_HT_AVAIL 24
+#define RES43239_XOLDO_PU 25
+#define RES43239_WL_XTAL_CTL_SEL 26
+#define RES43239_SR_CLK_STABLE 27
+#define RES43239_SR_SAVE_RESTORE 28
+#define RES43239_SR_PHY_PIC 29
+#define RES43239_SR_PHY_PWR_SW 30
#define CST43239_SPROM_MASK 0x00000002
@@ -1342,7 +1420,7 @@ typedef volatile struct {
#define CST43239_RES_INIT_MODE_SHIFT 7
#define CST43239_RES_INIT_MODE_MASK 0x000001f0
#define CST43239_CHIPMODE_SDIOD(cs) ((cs) & (1 << 15))
-#define CST43239_CHIPMODE_USB20D(cs) ((cs) & !(1 << 15))
+#define CST43239_CHIPMODE_USB20D(cs) (~(cs) & (1 << 15))
#define CST43239_CHIPMODE_SDIO(cs) (((cs) & (1 << 0)) == 0)
#define CST43239_CHIPMODE_GSPI(cs) (((cs) & (1 << 0)) == (1 << 0))
@@ -1350,6 +1428,40 @@ typedef volatile struct {
#define CCTRL43239_XTAL_STRENGTH(ctl) ((ctl & 0x3F) << 12)
+#define RES4331_REGULATOR 0
+#define RES4331_ILP_REQUEST 1
+#define RES4331_XTAL_PU 2
+#define RES4331_ALP_AVAIL 3
+#define RES4331_SI_PLL_ON 4
+#define RES4331_HT_SI_AVAIL 5
+
+
+#define CCTRL4331_BT_COEXIST (1<<0)
+#define CCTRL4331_SECI (1<<1)
+#define CCTRL4331_EXT_LNA_G (1<<2)
+#define CCTRL4331_SPROM_GPIO13_15 (1<<3)
+#define CCTRL4331_EXTPA_EN (1<<4)
+#define CCTRL4331_GPIOCLK_ON_SPROMCS <1<<5)
+#define CCTRL4331_PCIE_MDIO_ON_SPROMCS (1<<6)
+#define CCTRL4331_EXTPA_ON_GPIO2_5 (1<<7)
+#define CCTRL4331_OVR_PIPEAUXCLKEN (1<<8)
+#define CCTRL4331_OVR_PIPEAUXPWRDOWN (1<<9)
+#define CCTRL4331_PCIE_AUXCLKEN <1<<10)
+#define CCTRL4331_PCIE_PIPE_PLLDOWN <1<<11)
+#define CCTRL4331_EXTPA_EN2 (1<<12)
+#define CCTRL4331_EXT_LNA_A (1<<13)
+#define CCTRL4331_BT_SHD0_ON_GPIO4 <1<<16)
+#define CCTRL4331_BT_SHD1_ON_GPIO5 <1<<17)
+#define CCTRL4331_EXTPA_ANA_EN (1<<24)
+
+
+#define CST4331_XTAL_FREQ 0x00000001
+#define CST4331_SPROM_OTP_SEL_MASK 0x00000006
+#define CST4331_SPROM_OTP_SEL_SHIFT 1
+#define CST4331_SPROM_PRESENT 0x00000002
+#define CST4331_OTP_PRESENT 0x00000004
+#define CST4331_LDO_RF 0x00000008
+#define CST4331_LDO_PAR 0x00000010
#define RES4315_CBUCK_LPOM 1
@@ -1547,6 +1659,9 @@ typedef volatile struct {
#define CCTRL_4330_JTAG_DISABLE 0x00000008
+#define CCTRL_43239_GPIO_SEL 0x00000002
+#define CCTRL_43239_SDIO_HOST_WAKE 0x00000004
+
#define RES4313_BB_PU_RSRC 0
#define RES4313_ILP_REQ_RSRC 1
#define RES4313_XTAL_PU_RSRC 2
@@ -1597,6 +1712,54 @@ typedef volatile struct {
+#define SECI_MODE_UART 0x0
+#define SECI_MODE_SECI 0x1
+#define SECI_MODE_LEGACY_3WIRE_BT 0x2
+#define SECI_MODE_LEGACY_3WIRE_WLAN 0x3
+#define SECI_MODE_HALF_SECI 0x4
+
+#define SECI_RESET (1 << 0)
+#define SECI_RESET_BAR_UART (1 << 1)
+#define SECI_ENAB_SECI_ECI (1 << 2)
+#define SECI_ENAB_SECIOUT_DIS (1 << 3)
+#define SECI_MODE_MASK 0x7
+#define SECI_MODE_SHIFT 4
+#define SECI_UPD_SECI (1 << 7)
+
+
+#define CLKCTL_STS_SECI_CLK_REQ (1 << 8)
+#define CLKCTL_STS_SECI_CLK_AVAIL (1 << 24)
+
+#define SECI_UART_MSR_CTS_STATE (1 << 0)
+#define SECI_UART_MSR_RTS_STATE (1 << 1)
+#define SECI_UART_SECI_IN_STATE (1 << 2)
+#define SECI_UART_SECI_IN2_STATE (1 << 3)
+
+
+#define SECI_UART_LCR_STOP_BITS (1 << 0)
+#define SECI_UART_LCR_PARITY_EN (1 << 1)
+#define SECI_UART_LCR_PARITY (1 << 2)
+#define SECI_UART_LCR_RX_EN (1 << 3)
+#define SECI_UART_LCR_LBRK_CTRL (1 << 4)
+#define SECI_UART_LCR_TXO_EN (1 << 5)
+#define SECI_UART_LCR_RTSO_EN (1 << 6)
+#define SECI_UART_LCR_SLIPMODE_EN (1 << 7)
+#define SECI_UART_LCR_RXCRC_CHK (1 << 8)
+#define SECI_UART_LCR_TXCRC_INV (1 << 9)
+#define SECI_UART_LCR_TXCRC_LSBF (1 << 10)
+#define SECI_UART_LCR_TXCRC_EN (1 << 11)
+
+#define SECI_UART_MCR_TX_EN (1 << 0)
+#define SECI_UART_MCR_PRTS (1 << 1)
+#define SECI_UART_MCR_SWFLCTRL_EN (1 << 2)
+#define SECI_UART_MCR_HIGHRATE_EN (1 << 3)
+#define SECI_UART_MCR_LOOPBK_EN (1 << 4)
+#define SECI_UART_MCR_AUTO_RTS (1 << 5)
+#define SECI_UART_MCR_AUTO_TX_DIS (1 << 6)
+#define SECI_UART_MCR_BAUD_ADJ_EN (1 << 7)
+#define SECI_UART_MCR_XONOFF_RPT (1 << 9)
+
+
#define ECI_BW_20 0x0
diff --git a/drivers/net/wireless/bcmdhd/include/sbconfig.h b/drivers/net/wireless/bcmdhd/include/sbconfig.h
index 76f05ae34bd5..f45351a586cb 100644
--- a/drivers/net/wireless/bcmdhd/include/sbconfig.h
+++ b/drivers/net/wireless/bcmdhd/include/sbconfig.h
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: sbconfig.h,v 13.70 2008-03-28 19:17:04 Exp $
+ * $Id: sbconfig.h 277737 2011-08-16 17:54:59Z $
*/
diff --git a/drivers/net/wireless/bcmdhd/include/sbhnddma.h b/drivers/net/wireless/bcmdhd/include/sbhnddma.h
index 05d0587bc205..77c413f75f0d 100644
--- a/drivers/net/wireless/bcmdhd/include/sbhnddma.h
+++ b/drivers/net/wireless/bcmdhd/include/sbhnddma.h
@@ -22,7 +22,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: sbhnddma.h,v 13.20.2.3 2010-10-14 22:21:29 Exp $
+ * $Id: sbhnddma.h 278779 2011-08-19 22:07:18Z $
*/
@@ -217,7 +217,7 @@ typedef volatile struct {
#define D64_XC_BL_SHIFT 18
-#define D64_XP_LD_MASK 0x00000fff
+#define D64_XP_LD_MASK 0x00001fff
#define D64_XS0_CD_MASK 0x00001fff
@@ -260,7 +260,7 @@ typedef volatile struct {
#define DMA_CTRL_USB_BOUNDRY4KB_WAR (1 << 4)
-#define D64_RP_LD_MASK 0x00000fff
+#define D64_RP_LD_MASK 0x00001fff
#define D64_RS0_CD_MASK 0x00001fff
diff --git a/drivers/net/wireless/bcmdhd/include/sbpcmcia.h b/drivers/net/wireless/bcmdhd/include/sbpcmcia.h
index aba914bd014f..d84f69ab5617 100644
--- a/drivers/net/wireless/bcmdhd/include/sbpcmcia.h
+++ b/drivers/net/wireless/bcmdhd/include/sbpcmcia.h
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: sbpcmcia.h,v 13.48.12.6 2010-11-04 09:39:42 Exp $
+ * $Id: sbpcmcia.h 277737 2011-08-16 17:54:59Z $
*/
diff --git a/drivers/net/wireless/bcmdhd/include/sbsdio.h b/drivers/net/wireless/bcmdhd/include/sbsdio.h
index 4280d5bf9c1f..7aaeb73f0100 100644
--- a/drivers/net/wireless/bcmdhd/include/sbsdio.h
+++ b/drivers/net/wireless/bcmdhd/include/sbsdio.h
@@ -24,7 +24,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: sbsdio.h,v 13.34 2009-03-11 20:27:16 Exp $
+ * $Id: sbsdio.h 277737 2011-08-16 17:54:59Z $
*/
#ifndef _SBSDIO_H
diff --git a/drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h b/drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h
index 107a8b07c9e6..e5176483e9a1 100644
--- a/drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h
+++ b/drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h
@@ -22,7 +22,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: sbsdpcmdev.h,v 13.38 2009-09-22 22:56:45 Exp $
+ * $Id: sbsdpcmdev.h 282638 2011-09-08 21:18:10Z $
*/
#ifndef _sbsdpcmdev_h_
diff --git a/drivers/net/wireless/bcmdhd/include/sbsocram.h b/drivers/net/wireless/bcmdhd/include/sbsocram.h
index 1cba42238905..45c4dc208bda 100644
--- a/drivers/net/wireless/bcmdhd/include/sbsocram.h
+++ b/drivers/net/wireless/bcmdhd/include/sbsocram.h
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: sbsocram.h,v 13.15 2009-10-02 16:55:44 Exp $
+ * $Id: sbsocram.h 277737 2011-08-16 17:54:59Z $
*/
diff --git a/drivers/net/wireless/bcmdhd/include/sdio.h b/drivers/net/wireless/bcmdhd/include/sdio.h
index ca932266a1b2..c8ac7b773fb9 100644
--- a/drivers/net/wireless/bcmdhd/include/sdio.h
+++ b/drivers/net/wireless/bcmdhd/include/sdio.h
@@ -22,7 +22,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: sdio.h,v 13.27.14.1 2010-09-07 13:37:45 Exp $
+ * $Id: sdio.h 277737 2011-08-16 17:54:59Z $
*/
#ifndef _SDIO_H
@@ -366,7 +366,7 @@ typedef volatile struct {
* SDIO Commands and responses
*
* I/O only commands are:
- * CMD0, CMD3, CMD5, CMD7, CMD15, CMD52, CMD53
+ * CMD0, CMD3, CMD5, CMD7, CMD14, CMD15, CMD52, CMD53
* ------------------------------------------------
*/
@@ -412,6 +412,7 @@ typedef volatile struct {
#define CMD7_RCA_M BITFIELD_MASK(16)
#define CMD7_RCA_S 16
+
#define CMD14_RCA_M BITFIELD_MASK(16)
#define CMD14_RCA_S 16
#define CMD14_SLEEP_M BITFIELD_MASK(1)
diff --git a/drivers/net/wireless/bcmdhd/include/sdioh.h b/drivers/net/wireless/bcmdhd/include/sdioh.h
index 3d37c7a7e30b..5f47d6f88cea 100644
--- a/drivers/net/wireless/bcmdhd/include/sdioh.h
+++ b/drivers/net/wireless/bcmdhd/include/sdioh.h
@@ -22,7 +22,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: sdioh.h,v 13.17.2.3 2011-01-08 05:28:21 Exp $
+ * $Id: sdioh.h 300017 2011-12-01 20:30:27Z $
*/
#ifndef _SDIOH_H
@@ -68,6 +68,10 @@
#define SD_ADMA_SysAddr 0x58
#define SD_SlotInterruptStatus 0x0FC
#define SD_HostControllerVersion 0x0FE
+#define SD_GPIO_Reg 0x100
+#define SD_GPIO_OE 0x104
+#define SD_GPIO_Enable 0x108
+
/* SD specific registers in PCI config space */
#define SD_SlotInfo 0x40
@@ -409,4 +413,30 @@
/* SD_SlotInterruptStatus: Offset 0x0FC , size = bytes */
/* SD_HostControllerVersion : Offset 0x0FE , size = bytes */
+/* SDIO Host Control Register DMA Mode Definitions */
+#define SDIOH_SDMA_MODE 0
+#define SDIOH_ADMA1_MODE 1
+#define SDIOH_ADMA2_MODE 2
+#define SDIOH_ADMA2_64_MODE 3
+
+#define ADMA2_ATTRIBUTE_VALID (1 << 0) /* ADMA Descriptor line valid */
+#define ADMA2_ATTRIBUTE_END (1 << 1) /* End of Descriptor */
+#define ADMA2_ATTRIBUTE_INT (1 << 2) /* Interrupt when line is done */
+#define ADMA2_ATTRIBUTE_ACT_NOP (0 << 4) /* Skip current line, go to next. */
+#define ADMA2_ATTRIBUTE_ACT_RSV (1 << 4) /* Same as NOP */
+#define ADMA1_ATTRIBUTE_ACT_SET (1 << 4) /* ADMA1 Only - set transfer length */
+#define ADMA2_ATTRIBUTE_ACT_TRAN (2 << 4) /* Transfer Data of one descriptor line. */
+#define ADMA2_ATTRIBUTE_ACT_LINK (3 << 4) /* Link Descriptor */
+
+/* ADMA2 Descriptor Table Entry for 32-bit Address */
+typedef struct adma2_dscr_32b {
+ uint32 len_attr;
+ uint32 phys_addr;
+} adma2_dscr_32b_t;
+
+/* ADMA1 Descriptor Table Entry */
+typedef struct adma1_dscr {
+ uint32 phys_addr_attr;
+} adma1_dscr_t;
+
#endif /* _SDIOH_H */
diff --git a/drivers/net/wireless/bcmdhd/include/sdiovar.h b/drivers/net/wireless/bcmdhd/include/sdiovar.h
index 2c5bcf97e910..55a3d3490c30 100644
--- a/drivers/net/wireless/bcmdhd/include/sdiovar.h
+++ b/drivers/net/wireless/bcmdhd/include/sdiovar.h
@@ -22,7 +22,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: sdiovar.h,v 13.9 2009-12-08 22:30:15 Exp $
+ * $Id: sdiovar.h 277737 2011-08-16 17:54:59Z $
*/
#ifndef _sdiovar_h_
diff --git a/drivers/net/wireless/bcmdhd/include/siutils.h b/drivers/net/wireless/bcmdhd/include/siutils.h
index c5a33832b585..6a7b93c7b977 100644
--- a/drivers/net/wireless/bcmdhd/include/siutils.h
+++ b/drivers/net/wireless/bcmdhd/include/siutils.h
@@ -22,7 +22,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: siutils.h,v 13.251.2.10 2011-02-04 05:06:32 Exp $
+ * $Id: siutils.h 285387 2011-09-21 18:38:37Z $
*/
@@ -60,6 +60,7 @@ struct si_pub {
typedef const struct si_pub si_t;
+
#define SI_OSH NULL
#define BADIDX (SI_MAXCORES + 1)
@@ -213,8 +214,34 @@ extern int si_corepciid(si_t *sih, uint func, uint16 *pcivendor, uint16 *pcidevi
#define si_eci(sih) 0
#define si_eci_init(sih) (0)
#define si_eci_notify_bt(sih, type, val) (0)
+#define si_seci(sih) 0
+static INLINE void * si_seci_init(si_t *sih, uint8 use_seci) {return NULL;}
+#define si_seci_down(sih) do { } while (0)
+
+
+extern bool si_is_otp_disabled(si_t *sih);
+extern bool si_is_otp_powered(si_t *sih);
+extern void si_otp_power(si_t *sih, bool on);
+
+
+extern bool si_is_sprom_available(si_t *sih);
+extern bool si_is_sprom_enabled(si_t *sih);
+extern void si_sprom_enable(si_t *sih, bool enable);
+extern int si_cis_source(si_t *sih);
+#define CIS_DEFAULT 0
+#define CIS_SROM 1
+#define CIS_OTP 2
+
+
+#define DEFAULT_FAB 0x0
+#define CSM_FAB7 0x1
+#define TSMC_FAB12 0x2
+#define SMIC_FAB4 0x3
+extern int si_otp_fabid(si_t *sih, uint16 *fabid, bool rw);
+extern uint16 si_fabid(si_t *sih);
+
extern int si_devpath(si_t *sih, char *path, int size);
@@ -244,4 +271,5 @@ extern uint32 si_pcieserdesreg(si_t *sih, uint32 mdioslave, uint32 offset, uint3
char *si_getnvramflvar(si_t *sih, const char *name);
+
#endif
diff --git a/drivers/net/wireless/bcmdhd/include/trxhdr.h b/drivers/net/wireless/bcmdhd/include/trxhdr.h
index 397006ab005a..b52fb15ba5c0 100644
--- a/drivers/net/wireless/bcmdhd/include/trxhdr.h
+++ b/drivers/net/wireless/bcmdhd/include/trxhdr.h
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: trxhdr.h,v 13.15.108.2 2010-11-15 17:57:30 Exp $
+ * $Id: trxhdr.h 286295 2011-09-27 06:39:43Z $
*/
#ifndef _TRX_HDR_H_
@@ -37,6 +37,7 @@
#define TRX_OVERLAYS 0x4 /* Contains an overlay header after the trx header */
#define TRX_MAX_OFFSET 3 /* Max number of individual files */
#define TRX_UNCOMP_IMAGE 0x20 /* Trx contains uncompressed rtecdc.bin image */
+#define TRX_ROMSIM_IMAGE 0x10 /* Trx contains ROM simulation image */
struct trx_header {
uint32 magic; /* "HDR0" */
diff --git a/drivers/net/wireless/bcmdhd/include/typedefs.h b/drivers/net/wireless/bcmdhd/include/typedefs.h
index 228b5dcf11c7..d0902fe80891 100644
--- a/drivers/net/wireless/bcmdhd/include/typedefs.h
+++ b/drivers/net/wireless/bcmdhd/include/typedefs.h
@@ -18,7 +18,7 @@
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
- * $Id: typedefs.h,v 1.103.2.1 2010-05-11 18:19:28 Exp $
+ * $Id: typedefs.h 290055 2011-10-15 21:26:26Z $
*/
@@ -305,5 +305,8 @@ typedef float64 float_t;
#define UNUSED_PARAMETER(x) (void)(x)
+#define DISCARD_QUAL(ptr, type) ((type *)(uintptr)(ptr))
+
+
#include <bcmdefs.h>
#endif
diff --git a/drivers/net/wireless/bcmdhd/include/wlfc_proto.h b/drivers/net/wireless/bcmdhd/include/wlfc_proto.h
index 7230d3b67ab0..d37105165bab 100644
--- a/drivers/net/wireless/bcmdhd/include/wlfc_proto.h
+++ b/drivers/net/wireless/bcmdhd/include/wlfc_proto.h
@@ -18,7 +18,7 @@
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
-* $Id: wlfc_proto.h,v 1.1.6.2 2010-05-08 01:30:41 Exp $
+* $Id: wlfc_proto.h 277737 2011-08-16 17:54:59Z $
*
*/
#ifndef __wlfc_proto_definitions_h__
diff --git a/drivers/net/wireless/bcmdhd/include/wlioctl.h b/drivers/net/wireless/bcmdhd/include/wlioctl.h
index 9357552c9194..91274a0c680b 100644
--- a/drivers/net/wireless/bcmdhd/include/wlioctl.h
+++ b/drivers/net/wireless/bcmdhd/include/wlioctl.h
@@ -24,7 +24,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: wlioctl.h,v 1.767.2.38 2011-02-01 23:04:28 Exp $
+ * $Id: wlioctl.h 312596 2012-02-03 02:53:30Z $
*/
@@ -65,8 +65,8 @@ typedef struct wl_action_frame {
typedef struct ssid_info
{
- uint8 ssid_len;
- uint8 ssid[32];
+ uint8 ssid_len;
+ uint8 ssid[32];
} ssid_info_t;
typedef struct wl_af_params {
@@ -191,6 +191,7 @@ typedef struct wlc_ssid {
#define WL_SCANFLAGS_PROHIBITED 0x04
#define WL_SCAN_PARAMS_SSID_MAX 10
+
typedef struct wl_scan_params {
wlc_ssid_t ssid;
struct ether_addr bssid;
@@ -376,6 +377,8 @@ typedef struct {
#define NRATE_SGI_SHIFT 23
#define NRATE_LDPC_CODING 0x00400000
#define NRATE_LDPC_SHIFT 22
+#define NRATE_BCMC_OVERRIDE 0x00200000
+#define NRATE_BCMC_SHIFT 21
#define NRATE_STF_SISO 0
#define NRATE_STF_CDD 1
@@ -555,7 +558,7 @@ typedef enum sup_auth_status {
#define CRYPTO_ALGO_AES_OCB_MSDU 5
#define CRYPTO_ALGO_AES_OCB_MPDU 6
#define CRYPTO_ALGO_NALG 7
-#define CRYPTO_ALGO_PMK 12
+#define CRYPTO_ALGO_PMK 12
#define WSEC_GEN_MIC_ERROR 0x0001
#define WSEC_GEN_REPLAY 0x0002
@@ -617,9 +620,9 @@ typedef struct {
#define WPA2_AUTH_PSK 0x0080
#define BRCM_AUTH_PSK 0x0100
#define BRCM_AUTH_DPT 0x0200
-#define WPA2_AUTH_MFP 0x1000
-#define WPA2_AUTH_TPK 0x2000
-#define WPA2_AUTH_FT 0x4000
+#define WPA2_AUTH_MFP 0x1000
+#define WPA2_AUTH_TPK 0x2000
+#define WPA2_AUTH_FT 0x4000
#define MAXPMKID 16
@@ -649,12 +652,12 @@ typedef struct wl_assoc_info {
uint32 resp_len;
uint32 flags;
struct dot11_assoc_req req;
- struct ether_addr reassoc_bssid;
+ struct ether_addr reassoc_bssid;
struct dot11_assoc_resp resp;
} wl_assoc_info_t;
-#define WLC_ASSOC_REQ_IS_REASSOC 0x01
+#define WLC_ASSOC_REQ_IS_REASSOC 0x01
typedef struct {
@@ -818,8 +821,14 @@ typedef struct wlc_iov_trx_s {
#define WLC_IOCTL_MEDLEN 1536
#ifdef WLC_HIGH_ONLY
#define WLC_SAMPLECOLLECT_MAXLEN 1024
+#define WLC_SAMPLECOLLECT_MAXLEN_LCN40 1024
+#else
+#if defined(LCNCONF) || defined(LCN40CONF)
+#define WLC_SAMPLECOLLECT_MAXLEN 8192
#else
-#define WLC_SAMPLECOLLECT_MAXLEN 10240
+#define WLC_SAMPLECOLLECT_MAXLEN 10240
+#endif
+#define WLC_SAMPLECOLLECT_MAXLEN_LCN40 8192
#endif
@@ -851,6 +860,7 @@ typedef struct wlc_iov_trx_s {
#define WLC_GET_SSID 25
#define WLC_SET_SSID 26
#define WLC_RESTART 27
+#define WLC_TERMINATED 28
#define WLC_GET_CHANNEL 29
#define WLC_SET_CHANNEL 30
@@ -1203,7 +1213,7 @@ typedef struct {
#define WL_AUTH_OPEN_SYSTEM 0
#define WL_AUTH_SHARED_KEY 1
-#define WL_AUTH_OPEN_SHARED 2
+#define WL_AUTH_OPEN_SHARED 2
#define WL_RADIO_SW_DISABLE (1<<0)
@@ -1280,18 +1290,17 @@ typedef struct wl_po {
#define WL_CHAN_FREQ_RANGE_5GM 2
#define WL_CHAN_FREQ_RANGE_5GH 3
-#define WL_CHAN_FREQ_RANGE_5GLL_VER2 4
-#define WL_CHAN_FREQ_RANGE_5GLH_VER2 5
-#define WL_CHAN_FREQ_RANGE_5GML_VER2 6
-#define WL_CHAN_FREQ_RANGE_5GMH_VER2 7
-#define WL_CHAN_FREQ_RANGE_5GH_VER2 8
-
#define WL_CHAN_FREQ_RANGE_5GLL_5BAND 4
#define WL_CHAN_FREQ_RANGE_5GLH_5BAND 5
#define WL_CHAN_FREQ_RANGE_5GML_5BAND 6
#define WL_CHAN_FREQ_RANGE_5GMH_5BAND 7
#define WL_CHAN_FREQ_RANGE_5GH_5BAND 8
+#define WL_CHAN_FREQ_RANGE_5G_BAND0 1
+#define WL_CHAN_FREQ_RANGE_5G_BAND1 2
+#define WL_CHAN_FREQ_RANGE_5G_BAND2 3
+#define WL_CHAN_FREQ_RANGE_5G_BAND3 4
+
#define WLC_PHY_TYPE_A 0
#define WLC_PHY_TYPE_B 1
@@ -1363,7 +1372,7 @@ typedef struct wl_po {
#define PM_MAX 1
#define PM_FAST 2
-#define LISTEN_INTERVAL 10
+#define LISTEN_INTERVAL 10
#define INTERFERE_OVRRIDE_OFF -1
#define INTERFERE_NONE 0
@@ -1408,7 +1417,7 @@ typedef struct wl_aci_args {
#define TRIGGER_BADPLCP 0x10
#define TRIGGER_CRSGLITCH 0x20
#define WL_ACI_ARGS_LEGACY_LENGTH 16
-#define WL_SAMPLECOLLECT_T_VERSION 1
+#define WL_SAMPLECOLLECT_T_VERSION 2
typedef struct wl_samplecollect_args {
uint8 coll_us;
@@ -1416,7 +1425,7 @@ typedef struct wl_samplecollect_args {
uint16 version;
uint16 length;
- uint8 trigger;
+ int8 trigger;
uint16 timeout;
uint16 mode;
uint32 pre_dur;
@@ -1426,6 +1435,11 @@ typedef struct wl_samplecollect_args {
bool be_deaf;
bool agc;
bool filter;
+
+ uint8 trigger_state;
+ uint8 module_sel1;
+ uint8 module_sel2;
+ uint16 nsamps;
} wl_samplecollect_args_t;
#define WL_SAMPLEDATA_HEADER_TYPE 1
@@ -1493,6 +1507,7 @@ typedef struct wl_sampledata {
#define WL_P2P_VAL 0x00000200
#define WL_TXRX_VAL 0x00000400
#define WL_MCHAN_VAL 0x00000800
+#define WL_TDLS_VAL 0x00001000
#define WL_LED_NUMGPIO 16
@@ -1546,7 +1561,7 @@ typedef struct wl_sampledata {
#define WL_JOIN_PREF_WPA 2
#define WL_JOIN_PREF_BAND 3
#define WL_JOIN_PREF_RSSI_DELTA 4
-#define WL_JOIN_PREF_TRANS_PREF 5
+#define WL_JOIN_PREF_TRANS_PREF 5
#define WLJP_BAND_ASSOC_PREF 255
@@ -1797,17 +1812,19 @@ struct wl_msglevel2 {
};
typedef struct wl_mkeep_alive_pkt {
- uint16 version;
- uint16 length;
+ uint16 version;
+ uint16 length;
uint32 period_msec;
uint16 len_bytes;
- uint8 keep_alive_id;
+ uint8 keep_alive_id;
uint8 data[1];
} wl_mkeep_alive_pkt_t;
-#define WL_MKEEP_ALIVE_VERSION 1
-#define WL_MKEEP_ALIVE_FIXED_LEN OFFSETOF(wl_mkeep_alive_pkt_t, data)
-#define WL_MKEEP_ALIVE_PRECISION 500
+#define WL_MKEEP_ALIVE_VERSION 1
+#define WL_MKEEP_ALIVE_FIXED_LEN OFFSETOF(wl_mkeep_alive_pkt_t, data)
+#define WL_MKEEP_ALIVE_PRECISION 500
+
+
#define WLC_ROAM_TRIGGER_DEFAULT 0
#define WLC_ROAM_TRIGGER_BANDWIDTH 1
@@ -1897,7 +1914,7 @@ typedef struct wl_pfn_param {
uint8 mscan;
uint8 repeat;
uint8 exp;
- int32 slow_freq;
+ int32 slow_freq;
} wl_pfn_param_t;
typedef struct wl_pfn_bssid {
@@ -2016,8 +2033,31 @@ typedef struct wl_keep_alive_pkt {
+#define MAX_WAKE_PACKET_BYTES 128
+
+
+typedef struct pm_wake_packet {
+ uint32 status;
+ uint32 pattern_id;
+ uint32 original_packet_size;
+ uint32 saved_packet_size;
+ uchar packet[MAX_WAKE_PACKET_BYTES];
+} pm_wake_packet_t;
+
+
+
+#define PKT_FILTER_MODE_FORWARD_ON_MATCH 1
+
+#define PKT_FILTER_MODE_DISABLE 2
+
+#define PKT_FILTER_MODE_PKT_CACHE_ON_MATCH 4
+
+#define PKT_FILTER_MODE_PKT_FORWARD_OFF_DEFAULT 8
+
+
typedef enum wl_pkt_filter_type {
- WL_PKT_FILTER_TYPE_PATTERN_MATCH
+ WL_PKT_FILTER_TYPE_PATTERN_MATCH,
+ WL_PKT_FILTER_TYPE_MAGIC_PATTERN_MATCH
} wl_pkt_filter_type_t;
#define WL_PKT_FILTER_TYPE wl_pkt_filter_type_t
@@ -2550,6 +2590,12 @@ typedef struct wl_phycal_state {
#define WL_PHYCAL_STAT_FIXED_LEN OFFSETOF(wl_phycal_state_t, phycal_core)
#endif
+#ifdef WLDSTA
+typedef struct wl_dsta_if {
+ struct ether_addr addr;
+} wl_dsta_if_t;
+#endif
+
#ifdef WLP2P
typedef struct wl_p2p_disc_st {
diff --git a/drivers/net/wireless/bcmdhd/linux_osl.c b/drivers/net/wireless/bcmdhd/linux_osl.c
index 1a544378c1e6..4ef7bf7b24dc 100644
--- a/drivers/net/wireless/bcmdhd/linux_osl.c
+++ b/drivers/net/wireless/bcmdhd/linux_osl.c
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: linux_osl.c,v 1.168.2.7 2011-01-27 17:01:13 Exp $
+ * $Id: linux_osl.c,v 1.168.2.7 2011-01-27 17:01:13 $
*/
@@ -47,7 +47,7 @@
#define OS_HANDLE_MAGIC 0x1234abcd
#define BCM_MEM_FILENAME_LEN 24
-#ifdef DHD_USE_STATIC_BUF
+#ifdef CONFIG_DHD_USE_STATIC_BUF
#define STATIC_BUF_MAX_NUM 16
#define STATIC_BUF_SIZE (PAGE_SIZE * 2)
#define STATIC_BUF_TOTAL_LEN (STATIC_BUF_MAX_NUM * STATIC_BUF_SIZE)
@@ -70,7 +70,7 @@ typedef struct bcm_static_pkt {
} bcm_static_pkt_t;
static bcm_static_pkt_t *bcm_static_skb = 0;
-#endif
+#endif
typedef struct bcm_mem_link {
struct bcm_mem_link *prev;
@@ -211,7 +211,7 @@ osl_attach(void *pdev, uint bustype, bool pkttag)
break;
}
-#if defined(DHD_USE_STATIC_BUF)
+#if defined(CONFIG_DHD_USE_STATIC_BUF)
if (!bcm_static_buf) {
if (!(bcm_static_buf = (bcm_static_buf_t *)dhd_os_prealloc(osh, 3, STATIC_BUF_SIZE+
STATIC_BUF_TOTAL_LEN))) {
@@ -220,7 +220,6 @@ osl_attach(void *pdev, uint bustype, bool pkttag)
else
printk("alloc static buf at %x!\n", (unsigned int)bcm_static_buf);
-
sema_init(&bcm_static_buf->static_sem, 1);
bcm_static_buf->buf_ptr = (unsigned char *)bcm_static_buf + STATIC_BUF_SIZE;
@@ -238,7 +237,7 @@ osl_attach(void *pdev, uint bustype, bool pkttag)
sema_init(&bcm_static_skb->osl_pkt_sem, 1);
}
-#endif
+#endif
return osh;
}
@@ -388,7 +387,7 @@ osl_ctfpool_stats(osl_t *osh, void *b)
if ((osh == NULL) || (osh->ctfpool == NULL))
return;
-#ifdef DHD_USE_STATIC_BUF
+#ifdef CONFIG_DHD_USE_STATIC_BUF
if (bcm_static_buf) {
bcm_static_buf = 0;
}
@@ -548,14 +547,14 @@ osl_pktfree(osl_t *osh, void *p, bool send)
}
}
-#ifdef DHD_USE_STATIC_BUF
+#ifdef CONFIG_DHD_USE_STATIC_BUF
void *
osl_pktget_static(osl_t *osh, uint len)
{
int i;
struct sk_buff *skb;
- if (len > (PAGE_SIZE * 2)) {
+ if (!bcm_static_skb || (len > (PAGE_SIZE * 2))) {
printk("%s: attempt to allocate huge packet (0x%x)\n", __FUNCTION__, len);
return osl_pktget(osh, len);
}
@@ -570,10 +569,10 @@ osl_pktget_static(osl_t *osh, uint len)
if (i != STATIC_PKT_MAX_NUM) {
bcm_static_skb->pkt_use[i] = 1;
- up(&bcm_static_skb->osl_pkt_sem);
skb = bcm_static_skb->skb_4k[i];
skb->tail = skb->data + len;
skb->len = len;
+ up(&bcm_static_skb->osl_pkt_sem);
return skb;
}
}
@@ -586,10 +585,10 @@ osl_pktget_static(osl_t *osh, uint len)
if (i != STATIC_PKT_MAX_NUM) {
bcm_static_skb->pkt_use[i+STATIC_PKT_MAX_NUM] = 1;
- up(&bcm_static_skb->osl_pkt_sem);
skb = bcm_static_skb->skb_8k[i];
skb->tail = skb->data + len;
skb->len = len;
+ up(&bcm_static_skb->osl_pkt_sem);
return skb;
}
@@ -603,9 +602,14 @@ osl_pktfree_static(osl_t *osh, void *p, bool send)
{
int i;
+ if (!bcm_static_skb) {
+ osl_pktfree(osh, p, send);
+ return;
+ }
+
+ down(&bcm_static_skb->osl_pkt_sem);
for (i = 0; i < STATIC_PKT_MAX_NUM; i++) {
if (p == bcm_static_skb->skb_4k[i]) {
- down(&bcm_static_skb->osl_pkt_sem);
bcm_static_skb->pkt_use[i] = 0;
up(&bcm_static_skb->osl_pkt_sem);
return;
@@ -614,14 +618,15 @@ osl_pktfree_static(osl_t *osh, void *p, bool send)
for (i = 0; i < STATIC_PKT_MAX_NUM; i++) {
if (p == bcm_static_skb->skb_8k[i]) {
- down(&bcm_static_skb->osl_pkt_sem);
bcm_static_skb->pkt_use[i + STATIC_PKT_MAX_NUM] = 0;
up(&bcm_static_skb->osl_pkt_sem);
return;
}
}
+ up(&bcm_static_skb->osl_pkt_sem);
- return osl_pktfree(osh, p, send);
+ osl_pktfree(osh, p, send);
+ return;
}
#endif
diff --git a/drivers/net/wireless/bcmdhd/siutils.c b/drivers/net/wireless/bcmdhd/siutils.c
index 22aa41265763..a655ac4ef141 100644
--- a/drivers/net/wireless/bcmdhd/siutils.c
+++ b/drivers/net/wireless/bcmdhd/siutils.c
@@ -22,7 +22,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: siutils.c,v 1.813.2.36 2011-02-10 23:43:55 Exp $
+ * $Id: siutils.c,v 1.813.2.36 2011-02-10 23:43:55 $
*/
#include <typedefs.h>
@@ -213,11 +213,11 @@ si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin,
/* figure out bus/orignal core idx */
sii->pub.buscoretype = NODEV_CORE_ID;
- sii->pub.buscorerev = NOREV;
+ sii->pub.buscorerev = (uint)NOREV;
sii->pub.buscoreidx = BADIDX;
pci = pcie = FALSE;
- pcirev = pcierev = NOREV;
+ pcirev = pcierev = (uint)NOREV;
pciidx = pcieidx = BADIDX;
for (i = 0; i < sii->numcores; i++) {
@@ -365,6 +365,19 @@ si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs,
return NULL;
}
+#if defined(HW_OOB)
+ if (CHIPID(sih->chip) == BCM43362_CHIP_ID) {
+ uint32 gpiocontrol, addr;
+ addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, gpiocontrol);
+ gpiocontrol = bcmsdh_reg_read(sdh, addr, 4);
+ gpiocontrol |= 0x2;
+ bcmsdh_reg_write(sdh, addr, 4, gpiocontrol);
+ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, 0x10005, 0xf, NULL);
+ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, 0x10006, 0x0, NULL);
+ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, 0x10007, 0x2, NULL);
+ }
+#endif
+
if ((CHIPID(sih->chip) == BCM4329_CHIP_ID) && (sih->chiprev == 0) &&
(sih->chippkg != BCM4329_289PIN_PKG_ID)) {
sih->chippkg = BCM4329_182PIN_PKG_ID;
@@ -401,8 +414,9 @@ si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs,
}
/* assume current core is CC */
- if ((sii->pub.ccrev == 0x25) && ((CHIPID(sih->chip) == BCM43236_CHIP_ID ||
+ if ((sii->pub.ccrev == 0x25) && ((CHIPID(sih->chip) == BCM43234_CHIP_ID ||
CHIPID(sih->chip) == BCM43235_CHIP_ID ||
+ CHIPID(sih->chip) == BCM43236_CHIP_ID ||
CHIPID(sih->chip) == BCM43238_CHIP_ID) &&
(CHIPREV(sii->pub.chiprev) == 0))) {
@@ -1093,6 +1107,126 @@ si_watchdog_ms(si_t *sih, uint32 ms)
+/* return the slow clock source - LPO, XTAL, or PCI */
+static uint
+si_slowclk_src(si_info_t *sii)
+{
+ chipcregs_t *cc;
+
+ ASSERT(SI_FAST(sii) || si_coreid(&sii->pub) == CC_CORE_ID);
+
+ if (sii->pub.ccrev < 6) {
+ if ((BUSTYPE(sii->pub.bustype) == PCI_BUS) &&
+ (OSL_PCI_READ_CONFIG(sii->osh, PCI_GPIO_OUT, sizeof(uint32)) &
+ PCI_CFG_GPIO_SCS))
+ return (SCC_SS_PCI);
+ else
+ return (SCC_SS_XTAL);
+ } else if (sii->pub.ccrev < 10) {
+ cc = (chipcregs_t *)si_setcoreidx(&sii->pub, sii->curidx);
+ return (R_REG(sii->osh, &cc->slow_clk_ctl) & SCC_SS_MASK);
+ } else /* Insta-clock */
+ return (SCC_SS_XTAL);
+}
+
+/* return the ILP (slowclock) min or max frequency */
+static uint
+si_slowclk_freq(si_info_t *sii, bool max_freq, chipcregs_t *cc)
+{
+ uint32 slowclk;
+ uint div;
+
+ ASSERT(SI_FAST(sii) || si_coreid(&sii->pub) == CC_CORE_ID);
+
+ /* shouldn't be here unless we've established the chip has dynamic clk control */
+ ASSERT(R_REG(sii->osh, &cc->capabilities) & CC_CAP_PWR_CTL);
+
+ slowclk = si_slowclk_src(sii);
+ if (sii->pub.ccrev < 6) {
+ if (slowclk == SCC_SS_PCI)
+ return (max_freq ? (PCIMAXFREQ / 64) : (PCIMINFREQ / 64));
+ else
+ return (max_freq ? (XTALMAXFREQ / 32) : (XTALMINFREQ / 32));
+ } else if (sii->pub.ccrev < 10) {
+ div = 4 *
+ (((R_REG(sii->osh, &cc->slow_clk_ctl) & SCC_CD_MASK) >> SCC_CD_SHIFT) + 1);
+ if (slowclk == SCC_SS_LPO)
+ return (max_freq ? LPOMAXFREQ : LPOMINFREQ);
+ else if (slowclk == SCC_SS_XTAL)
+ return (max_freq ? (XTALMAXFREQ / div) : (XTALMINFREQ / div));
+ else if (slowclk == SCC_SS_PCI)
+ return (max_freq ? (PCIMAXFREQ / div) : (PCIMINFREQ / div));
+ else
+ ASSERT(0);
+ } else {
+ /* Chipc rev 10 is InstaClock */
+ div = R_REG(sii->osh, &cc->system_clk_ctl) >> SYCC_CD_SHIFT;
+ div = 4 * (div + 1);
+ return (max_freq ? XTALMAXFREQ : (XTALMINFREQ / div));
+ }
+ return (0);
+}
+
+static void
+si_clkctl_setdelay(si_info_t *sii, void *chipcregs)
+{
+ chipcregs_t *cc = (chipcregs_t *)chipcregs;
+ uint slowmaxfreq, pll_delay, slowclk;
+ uint pll_on_delay, fref_sel_delay;
+
+ pll_delay = PLL_DELAY;
+
+ /* If the slow clock is not sourced by the xtal then add the xtal_on_delay
+ * since the xtal will also be powered down by dynamic clk control logic.
+ */
+
+ slowclk = si_slowclk_src(sii);
+ if (slowclk != SCC_SS_XTAL)
+ pll_delay += XTAL_ON_DELAY;
+
+ /* Starting with 4318 it is ILP that is used for the delays */
+ slowmaxfreq = si_slowclk_freq(sii, (sii->pub.ccrev >= 10) ? FALSE : TRUE, cc);
+
+ pll_on_delay = ((slowmaxfreq * pll_delay) + 999999) / 1000000;
+ fref_sel_delay = ((slowmaxfreq * FREF_DELAY) + 999999) / 1000000;
+
+ W_REG(sii->osh, &cc->pll_on_delay, pll_on_delay);
+ W_REG(sii->osh, &cc->fref_sel_delay, fref_sel_delay);
+}
+
+/* initialize power control delay registers */
+void
+si_clkctl_init(si_t *sih)
+{
+ si_info_t *sii;
+ uint origidx = 0;
+ chipcregs_t *cc;
+ bool fast;
+
+ if (!CCCTL_ENAB(sih))
+ return;
+
+ sii = SI_INFO(sih);
+ fast = SI_FAST(sii);
+ if (!fast) {
+ origidx = sii->curidx;
+ if ((cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0)) == NULL)
+ return;
+ } else if ((cc = (chipcregs_t *)CCREGS_FAST(sii)) == NULL)
+ return;
+ ASSERT(cc != NULL);
+
+ /* set all Instaclk chip ILP to 1 MHz */
+ if (sih->ccrev >= 10)
+ SET_REG(sii->osh, &cc->system_clk_ctl, SYCC_CD_MASK,
+ (ILP_DIV_1MHZ << SYCC_CD_SHIFT));
+
+ si_clkctl_setdelay(sii, (void *)(uintptr)cc);
+
+ if (!fast)
+ si_setcoreidx(sih, origidx);
+}
+
/* change logical "focus" to the gpio core for optimized access */
void *
si_gpiosetcore(si_t *sih)
@@ -1718,3 +1852,64 @@ si_deviceremoved(si_t *sih)
}
return FALSE;
}
+
+bool
+si_is_sprom_available(si_t *sih)
+{
+ if (sih->ccrev >= 31) {
+ si_info_t *sii;
+ uint origidx;
+ chipcregs_t *cc;
+ uint32 sromctrl;
+
+ if ((sih->cccaps & CC_CAP_SROM) == 0)
+ return FALSE;
+
+ sii = SI_INFO(sih);
+ origidx = sii->curidx;
+ cc = si_setcoreidx(sih, SI_CC_IDX);
+ sromctrl = R_REG(sii->osh, &cc->sromcontrol);
+ si_setcoreidx(sih, origidx);
+ return (sromctrl & SRC_PRESENT);
+ }
+
+ switch (CHIPID(sih->chip)) {
+ case BCM4312_CHIP_ID:
+ return ((sih->chipst & CST4312_SPROM_OTP_SEL_MASK) != CST4312_OTP_SEL);
+ case BCM4325_CHIP_ID:
+ return (sih->chipst & CST4325_SPROM_SEL) != 0;
+ case BCM4322_CHIP_ID:
+ case BCM43221_CHIP_ID:
+ case BCM43231_CHIP_ID:
+ case BCM43222_CHIP_ID:
+ case BCM43111_CHIP_ID:
+ case BCM43112_CHIP_ID:
+ case BCM4342_CHIP_ID:
+ {
+ uint32 spromotp;
+ spromotp = (sih->chipst & CST4322_SPROM_OTP_SEL_MASK) >>
+ CST4322_SPROM_OTP_SEL_SHIFT;
+ return (spromotp & CST4322_SPROM_PRESENT) != 0;
+ }
+ case BCM4329_CHIP_ID:
+ return (sih->chipst & CST4329_SPROM_SEL) != 0;
+ case BCM4315_CHIP_ID:
+ return (sih->chipst & CST4315_SPROM_SEL) != 0;
+ case BCM4319_CHIP_ID:
+ return (sih->chipst & CST4319_SPROM_SEL) != 0;
+
+ case BCM4336_CHIP_ID:
+ case BCM43362_CHIP_ID:
+ return (sih->chipst & CST4336_SPROM_PRESENT) != 0;
+
+ case BCM4330_CHIP_ID:
+ return (sih->chipst & CST4330_SPROM_PRESENT) != 0;
+ case BCM4313_CHIP_ID:
+ return (sih->chipst & CST4313_SPROM_PRESENT) != 0;
+ case BCM43239_CHIP_ID:
+ return ((sih->chipst & CST43239_SPROM_MASK) &&
+ !(sih->chipst & CST43239_SFLASH_MASK));
+ default:
+ return TRUE;
+ }
+}
diff --git a/drivers/net/wireless/bcmdhd/wl_android.c b/drivers/net/wireless/bcmdhd/wl_android.c
index 9ca3d6020239..4fcdcd32a3ff 100644
--- a/drivers/net/wireless/bcmdhd/wl_android.c
+++ b/drivers/net/wireless/bcmdhd/wl_android.c
@@ -2,13 +2,13 @@
* Linux cfg80211 driver - Android related functions
*
* Copyright (C) 1999-2011, Broadcom Corporation
- *
+ *
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
- *
+ *
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
@@ -16,7 +16,7 @@
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
- *
+ *
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
@@ -67,13 +67,16 @@
#define CMD_BTCOEXSCAN_STOP "BTCOEXSCAN-STOP"
#define CMD_BTCOEXMODE "BTCOEXMODE"
#define CMD_SETSUSPENDOPT "SETSUSPENDOPT"
+#define CMD_SETSUSPENDMODE "SETSUSPENDMODE"
#define CMD_P2P_DEV_ADDR "P2P_DEV_ADDR"
#define CMD_SETFWPATH "SETFWPATH"
#define CMD_SETBAND "SETBAND"
#define CMD_GETBAND "GETBAND"
#define CMD_COUNTRY "COUNTRY"
#define CMD_P2P_SET_NOA "P2P_SET_NOA"
+#if !defined WL_ENABLE_P2P_IF
#define CMD_P2P_GET_NOA "P2P_GET_NOA"
+#endif
#define CMD_P2P_SET_PS "P2P_SET_PS"
#define CMD_SET_AP_WPS_P2P_IE "SET_AP_WPS_P2P_IE"
@@ -112,7 +115,7 @@ typedef struct android_wifi_priv_cmd {
*/
void dhd_customer_gpio_wlan_ctrl(int onoff);
uint dhd_dev_reset(struct net_device *dev, uint8 flag);
-void dhd_dev_init_ioctl(struct net_device *dev);
+int dhd_dev_init_ioctl(struct net_device *dev);
#ifdef WL_CFG80211
int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr);
int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command);
@@ -202,7 +205,7 @@ static int wl_android_set_suspendopt(struct net_device *dev, char *command, int
ret_now = net_os_set_suspend_disable(dev, suspend_flag);
if (ret_now != suspend_flag) {
- if (!(ret = net_os_set_suspend(dev, ret_now)))
+ if (!(ret = net_os_set_suspend(dev, ret_now, 1)))
DHD_INFO(("%s: Suspend Flag %d -> %d\n",
__FUNCTION__, ret_now, suspend_flag));
else
@@ -211,6 +214,26 @@ static int wl_android_set_suspendopt(struct net_device *dev, char *command, int
return ret;
}
+static int wl_android_set_suspendmode(struct net_device *dev, char *command, int total_len)
+{
+ int ret = 0;
+
+#if !defined(CONFIG_HAS_EARLYSUSPEND) || !defined(DHD_USE_EARLYSUSPEND)
+ int suspend_flag;
+
+ suspend_flag = *(command + strlen(CMD_SETSUSPENDMODE) + 1) - '0';
+
+ if (suspend_flag != 0)
+ suspend_flag = 1;
+
+ if (!(ret = net_os_set_suspend(dev, suspend_flag, 0)))
+ DHD_INFO(("%s: Suspend Mode %d\n",__FUNCTION__,suspend_flag));
+ else
+ DHD_ERROR(("%s: failed %d\n",__FUNCTION__,ret));
+#endif
+ return ret;
+}
+
static int wl_android_get_band(struct net_device *dev, char *command, int total_len)
{
uint band;
@@ -224,7 +247,7 @@ static int wl_android_get_band(struct net_device *dev, char *command, int total_
return bytes_written;
}
-#ifdef PNO_SUPPORT
+#if defined(PNO_SUPPORT) && !defined(WL_SCHED_SCAN)
static int wl_android_set_pno_setup(struct net_device *dev, char *command, int total_len)
{
wlc_ssid_t ssids_local[MAX_PFN_LIST_COUNT];
@@ -330,7 +353,7 @@ static int wl_android_set_pno_setup(struct net_device *dev, char *command, int t
exit_proc:
return res;
}
-#endif /* PNO_SUPPORT */
+#endif /* PNO_SUPPORT && !WL_SCHED_SCAN */
static int wl_android_get_p2p_dev_addr(struct net_device *ndev, char *command, int total_len)
{
@@ -364,8 +387,10 @@ int wl_android_wifi_on(struct net_device *dev)
sdioh_start(NULL, 0);
ret = dhd_dev_reset(dev, FALSE);
sdioh_start(NULL, 1);
- if (!ret)
- dhd_dev_init_ioctl(dev);
+ if (!ret) {
+ if (dhd_dev_init_ioctl(dev) < 0)
+ ret = -EFAULT;
+ }
g_wifi_on = 1;
}
dhd_net_if_unlock(dev);
@@ -506,6 +531,9 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
else if (strnicmp(command, CMD_SETSUSPENDOPT, strlen(CMD_SETSUSPENDOPT)) == 0) {
bytes_written = wl_android_set_suspendopt(net, command, priv_cmd.total_len);
}
+ else if (strnicmp(command, CMD_SETSUSPENDMODE, strlen(CMD_SETSUSPENDMODE)) == 0) {
+ bytes_written = wl_android_set_suspendmode(net, command, priv_cmd.total_len);
+ }
else if (strnicmp(command, CMD_SETBAND, strlen(CMD_SETBAND)) == 0) {
uint band = *(command + strlen(CMD_SETBAND) + 1) - '0';
bytes_written = wldev_set_band(net, band);
@@ -517,7 +545,7 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
char *country_code = command + strlen(CMD_COUNTRY) + 1;
bytes_written = wldev_set_country(net, country_code);
}
-#ifdef PNO_SUPPORT
+#if defined(PNO_SUPPORT) && !defined(WL_SCHED_SCAN)
else if (strnicmp(command, CMD_PNOSSIDCLR_SET, strlen(CMD_PNOSSIDCLR_SET)) == 0) {
bytes_written = dhd_dev_pno_reset(net);
}
@@ -537,9 +565,11 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip,
priv_cmd.total_len - skip);
}
+#if !defined WL_ENABLE_P2P_IF
else if (strnicmp(command, CMD_P2P_GET_NOA, strlen(CMD_P2P_GET_NOA)) == 0) {
bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len);
}
+#endif
else if (strnicmp(command, CMD_P2P_SET_PS, strlen(CMD_P2P_SET_PS)) == 0) {
int skip = strlen(CMD_P2P_SET_PS) + 1;
bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip,
@@ -559,8 +589,10 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
bytes_written = strlen("OK");
}
- if (bytes_written > 0) {
- if (bytes_written > priv_cmd.total_len) {
+ if (bytes_written >= 0) {
+ if ((bytes_written == 0) && (priv_cmd.total_len > 0))
+ command[0] = '\0';
+ if (bytes_written >= priv_cmd.total_len) {
DHD_ERROR(("%s: bytes_written = %d\n", __FUNCTION__, bytes_written));
bytes_written = priv_cmd.total_len;
} else {
@@ -571,7 +603,8 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
DHD_ERROR(("%s: failed to copy data to user buffer\n", __FUNCTION__));
ret = -EFAULT;
}
- } else {
+ }
+ else {
ret = bytes_written;
}
@@ -588,7 +621,7 @@ int wl_android_init(void)
{
int ret = 0;
- dhd_msg_level = DHD_ERROR_VAL;
+ dhd_msg_level |= DHD_ERROR_VAL;
#ifdef ENABLE_INSMOD_NO_FW_LOAD
dhd_download_fw_on_driverload = FALSE;
#endif /* ENABLE_INSMOD_NO_FW_LOAD */
@@ -608,30 +641,14 @@ int wl_android_exit(void)
return ret;
}
-int wl_android_post_init(void)
+void wl_android_post_init(void)
{
- struct net_device *ndev;
- int ret = 0;
- char buf[IFNAMSIZ];
if (!dhd_download_fw_on_driverload) {
/* Call customer gpio to turn off power with WL_REG_ON signal */
dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF);
g_wifi_on = 0;
- } else {
- memset(buf, 0, IFNAMSIZ);
-#ifdef CUSTOMER_HW2
- snprintf(buf, IFNAMSIZ, "%s%d", iface_name, 0);
-#else
- snprintf(buf, IFNAMSIZ, "%s%d", "eth", 0);
-#endif
- if ((ndev = dev_get_by_name (&init_net, buf)) != NULL) {
- dhd_dev_init_ioctl(ndev);
- dev_put(ndev);
- }
}
- return ret;
}
-
/**
* Functions for Android WiFi card detection
*/
@@ -682,13 +699,14 @@ void* wl_android_prealloc(int section, unsigned long size)
alloc_ptr = wifi_control_data->mem_prealloc(section, size);
if (alloc_ptr) {
DHD_INFO(("success alloc section %d\n", section));
- bzero(alloc_ptr, size);
+ if (size != 0L)
+ bzero(alloc_ptr, size);
return alloc_ptr;
}
}
DHD_ERROR(("can't alloc section %d\n", section));
- return 0;
+ return NULL;
}
int wifi_get_irq_number(unsigned long *irq_flags_ptr)
@@ -787,7 +805,7 @@ static int wifi_remove(struct platform_device *pdev)
static int wifi_suspend(struct platform_device *pdev, pm_message_t state)
{
DHD_TRACE(("##> %s\n", __FUNCTION__));
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY)
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY)
bcmsdh_oob_intr_set(0);
#endif
return 0;
@@ -796,7 +814,7 @@ static int wifi_suspend(struct platform_device *pdev, pm_message_t state)
static int wifi_resume(struct platform_device *pdev)
{
DHD_TRACE(("##> %s\n", __FUNCTION__));
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY)
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY)
if (dhd_os_check_if_up(bcmsdh_get_drvdata()))
bcmsdh_oob_intr_set(1);
#endif
diff --git a/drivers/net/wireless/bcmdhd/wl_android.h b/drivers/net/wireless/bcmdhd/wl_android.h
index 17373b7f6d5b..3983306cfe38 100644
--- a/drivers/net/wireless/bcmdhd/wl_android.h
+++ b/drivers/net/wireless/bcmdhd/wl_android.h
@@ -40,7 +40,7 @@
*/
int wl_android_init(void);
int wl_android_exit(void);
-int wl_android_post_init(void);
+void wl_android_post_init(void);
int wl_android_wifi_on(struct net_device *dev);
int wl_android_wifi_off(struct net_device *dev);
int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd);
diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c
index 04affb50b18b..f728c14622a1 100644
--- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c
+++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c
@@ -2,13 +2,13 @@
* Linux cfg80211 driver
*
* Copyright (C) 1999-2011, Broadcom Corporation
- *
+ *
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
- *
+ *
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
@@ -41,10 +41,9 @@
#include <dhd.h>
#include <dhdioctl.h>
#include <wlioctl.h>
+#include <dhd_cfg80211.h>
#include <proto/ethernet.h>
-#include <dngl_stats.h>
-#include <dhd.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/netdevice.h>
@@ -54,54 +53,29 @@
#include <linux/ieee80211.h>
#include <linux/wait.h>
#include <net/cfg80211.h>
-
#include <net/rtnetlink.h>
-#include <linux/mmc/sdio_func.h>
-#include <linux/firmware.h>
-#include <bcmsdbus.h>
#include <wlioctl.h>
#include <wldev_common.h>
#include <wl_cfg80211.h>
#include <wl_cfgp2p.h>
-static struct sdio_func *cfg80211_sdio_func;
-static struct wl_priv *wlcfg_drv_priv;
+static struct device *cfg80211_parent_dev = NULL;
+static int vsdb_supported = 0;
+struct wl_priv *wlcfg_drv_priv = NULL;
u32 wl_dbg_level = WL_DBG_ERR;
-#define WL_4329_FW_FILE "brcm/bcm4329-fullmac-4-218-248-5.bin"
-#define WL_4329_NVRAM_FILE "brcm/bcm4329-fullmac-4-218-248-5.txt"
#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
#define MAX_WAIT_TIME 1500
-static s8 ioctlbuf[WLC_IOCTL_MAXLEN];
+#define WL_SCAN_ACTIVE_TIME 40
+#define WL_SCAN_PASSIVE_TIME 130
+#define WL_FRAME_LEN 300
+#define DNGL_FUNC(func, parameters) func parameters;
#define COEX_DHCP
-#if defined(COEX_DHCP)
-#define BT_DHCP_eSCO_FIX /* use New SCO/eSCO smart YG
- * suppression
- */
-#define BT_DHCP_USE_FLAGS /* this flag boost wifi pkt priority
- * to max, caution: -not fair to sco
- */
-#define BT_DHCP_OPPR_WIN_TIME 2500 /* T1 start SCO/ESCo priority
- * suppression
- */
-#define BT_DHCP_FLAG_FORCE_TIME 5500 /* T2 turn off SCO/SCO supperesion
- * is (timeout)
- */
-enum wl_cfg80211_btcoex_status {
- BT_DHCP_IDLE,
- BT_DHCP_START,
- BT_DHCP_OPPR_WIN,
- BT_DHCP_FLAG_FORCE_TIMEOUT
-};
-
-static int wl_cfg80211_btcoex_init(struct wl_priv *wl);
-static void wl_cfg80211_btcoex_deinit(struct wl_priv *wl);
-#endif
/* This is to override regulatory domains defined in cfg80211 module (reg.c)
* By default world regulatory domain defined in reg.c puts the flags NL80211_RRF_PASSIVE_SCAN
@@ -121,8 +95,10 @@ static const struct ieee80211_regdomain brcm_regdom = {
REG_RULE(2467-10, 2472+10, 20, 6, 20,
NL80211_RRF_PASSIVE_SCAN |
NL80211_RRF_NO_IBSS),
- /* IEEE 802.11 channel 14 - Only JP enables
- * this and for 802.11b only
+ /*
+ * IEEE 802.11 channel 14 - is for JP only,
+ * we need cfg80211 to allow it (reg_flags = 0); so that
+ * hostapd could request auto channel by sending down ch 14
*/
REG_RULE(2484-10, 2484+10, 20, 6, 20,
NL80211_RRF_PASSIVE_SCAN |
@@ -224,7 +200,8 @@ static s32 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_pmksa *pmksa);
static s32 wl_cfg80211_flush_pmksa(struct wiphy *wiphy,
struct net_device *dev);
-static void wl_notify_escan_complete(struct wl_priv *wl, bool aborted);
+static s32 wl_notify_escan_complete(struct wl_priv *wl,
+ struct net_device *ndev, bool aborted, bool fw_abort);
/*
* event & event Q handlers for cfg80211 interfaces
*/
@@ -242,6 +219,8 @@ static s32 wl_enq_event(struct wl_priv *wl, struct net_device *ndev, u32 type,
const wl_event_msg_t *msg, void *data);
static void wl_put_event(struct wl_event_q *e);
static void wl_wakeup_event(struct wl_priv *wl);
+static s32 wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data);
static s32 wl_notify_connect_status(struct wl_priv *wl,
struct net_device *ndev,
const wl_event_msg_t *e, void *data);
@@ -256,22 +235,19 @@ static s32 wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev,
const wl_event_msg_t *e, void *data);
static s32 wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev,
const wl_event_msg_t *e, void *data);
+#ifdef WL_SCHED_SCAN
+static s32
+wl_notify_sched_scan_results(struct wl_priv *wl, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data);
+#endif /* WL_SCHED_SCAN */
+#ifdef PNO_SUPPORT
+static s32 wl_notify_pfn_status(struct wl_priv *wl, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data);
+#endif /* PNO_SUPPORT */
/*
- * register/deregister sdio function
- */
-struct sdio_func *wl_cfg80211_get_sdio_func(void);
-static void wl_clear_sdio_func(void);
-
-/*
- * ioctl utilites
+ * register/deregister parent device
*/
-static s32 wl_dev_bufvar_get(struct net_device *dev, s8 *name, s8 *buf,
- s32 buf_len);
-static __used s32 wl_dev_bufvar_set(struct net_device *dev, s8 *name,
- s8 *buf, s32 len);
-static s32 wl_dev_intvar_set(struct net_device *dev, s8 *name, s32 val);
-static s32 wl_dev_intvar_get(struct net_device *dev, s8 *name,
- s32 *retval);
+static void wl_cfg80211_clear_parent_dev(void);
/*
* cfg80211 set_wiphy_params utilities
@@ -283,10 +259,10 @@ static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l);
/*
* wl profile utilities
*/
-static s32 wl_update_prof(struct wl_priv *wl, const wl_event_msg_t *e,
- void *data, s32 item);
-static void *wl_read_prof(struct wl_priv *wl, s32 item);
-static void wl_init_prof(struct wl_priv *wl);
+static s32 wl_update_prof(struct wl_priv *wl, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data, s32 item);
+static void *wl_read_prof(struct wl_priv *wl, struct net_device *ndev, s32 item);
+static void wl_init_prof(struct wl_priv *wl, struct net_device *ndev);
/*
* cfg80211 connect utilites
@@ -314,14 +290,14 @@ static s32 wl_mrg_ie(struct wl_priv *wl, u8 *ie_stream, u16 ie_size);
static s32 wl_cp_ie(struct wl_priv *wl, u8 *dst, u16 dst_size);
static u32 wl_get_ielen(struct wl_priv *wl);
-static s32 wl_mode_to_nl80211_iftype(s32 mode);
-static struct wireless_dev *wl_alloc_wdev(struct device *sdiofunc_dev);
+static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *dev);
static void wl_free_wdev(struct wl_priv *wl);
static s32 wl_inform_bss(struct wl_priv *wl);
static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi);
static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev);
+static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy);
static s32 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
u8 key_idx, const u8 *mac_addr,
@@ -347,42 +323,19 @@ static bool wl_is_ibssmode(struct wl_priv *wl, struct net_device *ndev);
static __used bool wl_is_ibssstarter(struct wl_priv *wl);
/*
- * dongle up/down , default configuration utilities
+ * link up/down , default configuration utilities
*/
+static s32 __wl_cfg80211_up(struct wl_priv *wl);
+static s32 __wl_cfg80211_down(struct wl_priv *wl);
+static s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add);
static bool wl_is_linkdown(struct wl_priv *wl, const wl_event_msg_t *e);
static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e, struct net_device *ndev);
static bool wl_is_nonetwork(struct wl_priv *wl, const wl_event_msg_t *e);
static void wl_link_up(struct wl_priv *wl);
static void wl_link_down(struct wl_priv *wl);
-static s32 wl_dongle_mode(struct wl_priv *wl, struct net_device *ndev, s32 iftype);
-static s32 __wl_cfg80211_up(struct wl_priv *wl);
-static s32 __wl_cfg80211_down(struct wl_priv *wl);
-static s32 wl_dongle_probecap(struct wl_priv *wl);
+static s32 wl_config_ifmode(struct wl_priv *wl, struct net_device *ndev, s32 iftype);
static void wl_init_conf(struct wl_conf *conf);
-static s32 wl_dongle_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add);
-
-/*
- * dongle configuration utilities
- */
-#ifndef EMBEDDED_PLATFORM
-static s32 wl_dongle_country(struct net_device *ndev, u8 ccode);
-static s32 wl_dongle_up(struct net_device *ndev, u32 up);
-static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode);
-static s32 wl_dongle_glom(struct net_device *ndev, u32 glom,
- u32 dongle_align);
-static s32 wl_dongle_roam(struct net_device *ndev, u32 roamvar,
- u32 bcn_timeout);
-static s32 wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
- s32 scan_unassoc_time);
-static s32 wl_dongle_offload(struct net_device *ndev, s32 arpoe,
- s32 arp_ol);
-static s32 wl_pattern_atoh(s8 *src, s8 *dst);
-static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode);
static s32 wl_update_wiphybands(struct wl_priv *wl);
-#endif /* !EMBEDDED_PLATFORM */
-static __used void wl_dongle_poweron(struct wl_priv *wl);
-static __used void wl_dongle_poweroff(struct wl_priv *wl);
-static s32 wl_config_dongle(struct wl_priv *wl, bool need_lock);
/*
* iscan handler
@@ -406,33 +359,20 @@ static s32 wl_iscan_inprogress(struct wl_priv *wl);
static s32 wl_iscan_aborted(struct wl_priv *wl);
/*
- * fw/nvram downloading handler
- */
-static void wl_init_fw(struct wl_fw_ctrl *fw);
-
-/*
* find most significant bit set
*/
static __used u32 wl_find_msb(u16 bit16);
/*
- * update pmklist to dongle
- */
-static __used s32 wl_update_pmklist(struct net_device *dev,
- struct wl_pmk_list *pmk_list, s32 err);
-
-/*
- * debufs support
- */
-static int wl_debugfs_add_netdev_params(struct wl_priv *wl);
-static void wl_debugfs_remove_netdev(struct wl_priv *wl);
-
-/*
* rfkill support
*/
static int wl_setup_rfkill(struct wl_priv *wl, bool setup);
static int wl_rfkill_set(void *data, bool blocked);
+static wl_scan_params_t *wl_cfg80211_scan_alloc_params(int channel,
+ int nprobes, int *out_params_size);
+static void get_primary_mac(struct wl_priv *wl, struct ether_addr *mac);
+
/*
* Some external functions, TODO: move them to dhd_linux.h
*/
@@ -444,10 +384,10 @@ int dhd_start_xmit(struct sk_buff *skb, struct net_device *net);
#define CHECK_SYS_UP(wlpriv) \
do { \
- if (unlikely(!wl_get_drv_status(wlpriv, READY))) { \
- WL_INFO(("device is not ready : status (%d)\n", \
- (int)wlpriv->status)); \
- return -EIO; \
+ struct net_device *ndev = wl_to_prmry_ndev(wlpriv); \
+ if (unlikely(!wl_get_drv_status(wlpriv, READY, ndev))) { \
+ WL_INFO(("device is not ready\n")); \
+ return -EIO; \
} \
} while (0)
@@ -740,6 +680,43 @@ wl_validate_wps_ie(char *wps_ie, bool *pbc)
}
}
+static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy)
+{
+ if (vsdb_supported) {
+ return wf_chspec_aton(WL_P2P_TEMP_CHAN);
+ }
+ else {
+ chanspec_t chspec;
+ int err = 0;
+ struct wl_priv *wl = wiphy_priv(wiphy);
+ struct net_device *dev = wl_to_prmry_ndev(wl);
+ struct ether_addr bssid;
+ struct wl_bss_info *bss = NULL;
+ if ((err = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, sizeof(bssid), false))) {
+ /* STA interface is not associated. So start the new interface on a temp
+ * channel . Later proper channel will be applied by the above framework
+ * via set_channel (cfg80211 API).
+ */
+ WL_DBG(("Not associated. Return a temp channel. \n"));
+ return wf_chspec_aton(WL_P2P_TEMP_CHAN);
+ }
+
+
+ *(u32 *) wl->extra_buf = htod32(WL_EXTRA_BUF_MAX);
+ if ((err = wldev_ioctl(dev, WLC_GET_BSS_INFO, wl->extra_buf,
+ sizeof(WL_EXTRA_BUF_MAX), false))) {
+ WL_ERR(("Failed to get associated bss info, use temp channel \n"));
+ chspec = wf_chspec_aton(WL_P2P_TEMP_CHAN);
+ }
+ else {
+ bss = (struct wl_bss_info *) (wl->extra_buf + 4);
+ chspec = bss->chanspec;
+ WL_DBG(("Valid BSS Found. chanspec:%d \n", bss->chanspec));
+ }
+ return chspec;
+ }
+}
+
static struct net_device* wl_cfg80211_add_monitor_if(char *name)
{
int ret = 0;
@@ -758,15 +735,20 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
s32 err;
s32 timeout = -1;
s32 wlif_type = -1;
- s32 index = 0;
s32 mode = 0;
+#if defined(WL_ENABLE_P2P_IF)
+ s32 dhd_mode = 0;
+#endif /* (WL_ENABLE_P2P_IF) */
chanspec_t chspec;
struct wl_priv *wl = wiphy_priv(wiphy);
struct net_device *_ndev;
- dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
- int (*net_attach)(dhd_pub_t *dhdp, int ifidx);
+ struct ether_addr primary_mac;
+ int (*net_attach)(void *dhdp, int ifidx);
bool rollback_lock = false;
+ /* Use primary I/F for sending cmds down to firmware */
+ _ndev = wl_to_prmry_ndev(wl);
+
WL_DBG(("if name: %s, type: %d\n", name, type));
switch (type) {
case NL80211_IFTYPE_ADHOC:
@@ -798,6 +780,8 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
WL_ERR(("name is NULL\n"));
return NULL;
}
+ if (wl->iface_cnt == IFACE_MAX_CNT)
+ return ERR_PTR(-ENOMEM);
if (wl->p2p_supported && (wlif_type != -1)) {
if (wl_get_p2p_status(wl, IF_DELETING)) {
/* wait till IF_DEL is complete
@@ -809,7 +793,7 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
}
WL_INFO(("%s: Released the lock and wait till IF_DEL is complete\n",
__func__));
- timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
+ timeout = wait_event_interruptible_timeout(wl->netif_change_event,
(wl_get_p2p_status(wl, IF_DELETING) == false),
msecs_to_jiffies(MAX_WAIT_TIME));
@@ -826,17 +810,25 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
return ERR_PTR(-EAGAIN);
}
}
- if (!p2p_on(wl) && strstr(name, WL_P2P_INTERFACE_PREFIX)) {
+ if (wl->p2p && !wl->p2p->on && strstr(name, WL_P2P_INTERFACE_PREFIX)) {
p2p_on(wl) = true;
wl_cfgp2p_set_firm_p2p(wl);
wl_cfgp2p_init_discovery(wl);
+ get_primary_mac(wl, &primary_mac);
+ wl_cfgp2p_generate_bss_mac(&primary_mac,
+ &wl->p2p->dev_addr, &wl->p2p->int_addr);
}
+
memset(wl->p2p->vir_ifname, 0, IFNAMSIZ);
strncpy(wl->p2p->vir_ifname, name, IFNAMSIZ - 1);
- wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr);
- /* Temporary use channel 11, in case GO will be changed with set_channel API */
- chspec = wf_chspec_aton(WL_P2P_TEMP_CHAN);
+ wldev_iovar_setint(_ndev, "mpc", 0);
+ wl_notify_escan_complete(wl, _ndev, true, true);
+ /* In concurrency case, STA may be already associated in a particular channel.
+ * so retrieve the current channel of primary interface and then start the virtual
+ * interface on that.
+ */
+ chspec = wl_cfg80211_get_shared_freq(wiphy);
/* For P2P mode, use P2P-specific driver features to create the
* bss: "wl p2p_ifadd"
@@ -844,10 +836,12 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
wl_set_p2p_status(wl, IF_ADD);
err = wl_cfgp2p_ifadd(wl, &wl->p2p->int_addr, htod32(wlif_type), chspec);
- if (unlikely(err))
+ if (unlikely(err)) {
+ WL_ERR((" virtual iface add failed (%d) \n", err));
return ERR_PTR(-ENOMEM);
+ }
- timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
+ timeout = wait_event_interruptible_timeout(wl->netif_change_event,
(wl_get_p2p_status(wl, IF_ADD) == false),
msecs_to_jiffies(MAX_WAIT_TIME));
if (timeout > 0 && (!wl_get_p2p_status(wl, IF_ADD))) {
@@ -860,27 +854,37 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
}
vwdev->wiphy = wl->wdev->wiphy;
WL_INFO((" virtual interface(%s) is created memalloc done \n",
- wl->p2p->vir_ifname));
- index = alloc_idx_vwdev(wl);
- wl->vwdev[index] = vwdev;
- vwdev->iftype =
- (wlif_type == WL_P2P_IF_CLIENT) ? NL80211_IFTYPE_STATION
- : NL80211_IFTYPE_AP;
+ wl->p2p->vir_ifname));
+ vwdev->iftype = type;
_ndev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION);
_ndev->ieee80211_ptr = vwdev;
SET_NETDEV_DEV(_ndev, wiphy_dev(vwdev->wiphy));
vwdev->netdev = _ndev;
- wl_set_drv_status(wl, READY);
+ wl_set_drv_status(wl, READY, _ndev);
wl->p2p->vif_created = true;
- set_mode_by_netdev(wl, _ndev, mode);
+ wl_set_mode_by_netdev(wl, _ndev, mode);
net_attach = wl_to_p2p_bss_private(wl, P2PAPI_BSSCFG_CONNECTION);
if (rtnl_is_locked()) {
rtnl_unlock();
rollback_lock = true;
}
- if (net_attach && !net_attach(dhd, _ndev->ifindex)) {
- WL_DBG((" virtual interface(%s) is "
+ if (net_attach && !net_attach(wl->pub, _ndev->ifindex)) {
+ wl_alloc_netinfo(wl, _ndev, vwdev, mode);
+ WL_ERR((" virtual interface(%s) is "
"created net attach done\n", wl->p2p->vir_ifname));
+#if defined(WL_ENABLE_P2P_IF)
+ if (type == NL80211_IFTYPE_P2P_CLIENT)
+ dhd_mode = P2P_GC_ENABLED;
+ else if (type == NL80211_IFTYPE_P2P_GO)
+ dhd_mode = P2P_GO_ENABLED;
+ DNGL_FUNC(dhd_cfg80211_set_p2p_info, (wl, dhd_mode));
+#endif /* (WL_ENABLE_P2P_IF) */
+ /* Start the P2P I/F with PM disabled. Enable PM from
+ * the framework
+ */
+ if ((type == NL80211_IFTYPE_P2P_CLIENT) || (
+ type == NL80211_IFTYPE_P2P_GO))
+ vwdev->ps = NL80211_PS_DISABLED;
} else {
/* put back the rtnl_lock again */
if (rollback_lock)
@@ -911,34 +915,46 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev)
s32 timeout = -1;
s32 ret = 0;
WL_DBG(("Enter\n"));
+
+ if (wl->p2p_net == dev) {
+ /* Since there is no ifidx corresponding to p2p0, cmds to
+ * firmware should be routed through primary I/F
+ */
+ dev = wl_to_prmry_ndev(wl);
+ }
+
if (wl->p2p_supported) {
memcpy(p2p_mac.octet, wl->p2p->int_addr.octet, ETHER_ADDR_LEN);
if (wl->p2p->vif_created) {
- if (wl_get_drv_status(wl, SCANNING)) {
- wl_cfg80211_scan_abort(wl, dev);
+ if (wl_get_drv_status(wl, SCANNING, dev)) {
+ wl_notify_escan_complete(wl, dev, true, true);
}
wldev_iovar_setint(dev, "mpc", 1);
wl_set_p2p_status(wl, IF_DELETING);
ret = wl_cfgp2p_ifdel(wl, &p2p_mac);
- if (ret) {
/* Firmware could not delete the interface so we will not get WLC_E_IF
* event for cleaning the dhd virtual nw interace
* So lets do it here. Failures from fw will ensure the application to do
* ifconfig <inter> down and up sequnce, which will reload the fw
* however we should cleanup the linux network virtual interfaces
*/
- dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
- WL_ERR(("Firmware returned an error from p2p_ifdel\n"));
- WL_ERR(("try to remove linux virtual interface %s\n", dev->name));
- dhd_del_if(dhd->info, dhd_net2idx(dhd->info, dev));
+ /* Request framework to RESET and clean up */
+ if (ret) {
+ struct net_device *ndev = wl_to_prmry_ndev(wl);
+ WL_ERR(("Firmware returned an error (%d) from p2p_ifdel"
+ "HANG Notification sent to %s\n", ret, ndev->name));
+ wl_cfg80211_hang(ndev, WLAN_REASON_UNSPECIFIED);
}
/* Wait for any pending scan req to get aborted from the sysioc context */
- timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
- (wl_get_p2p_status(wl, IF_DELETING) == false),
+ timeout = wait_event_interruptible_timeout(wl->netif_change_event,
+ (wl->p2p->vif_created == false),
msecs_to_jiffies(MAX_WAIT_TIME));
- if (timeout > 0 && !wl_get_p2p_status(wl, IF_DELETING)) {
+ if (timeout > 0 && (wl->p2p->vif_created == false)) {
WL_DBG(("IFDEL operation done\n"));
+#if defined(WL_ENABLE_P2P_IF)
+ DNGL_FUNC(dhd_cfg80211_clean_p2p_info, (wl));
+#endif /* (WL_ENABLE_P2P_IF)) */
} else {
WL_ERR(("IFDEL didn't complete properly\n"));
}
@@ -961,7 +977,8 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
s32 mode = 0;
chanspec_t chspec;
struct wl_priv *wl = wiphy_priv(wiphy);
- WL_DBG(("Enter \n"));
+
+ WL_DBG(("Enter type %d\n", type));
switch (type) {
case NL80211_IFTYPE_MONITOR:
case NL80211_IFTYPE_WDS:
@@ -988,28 +1005,35 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
return -EINVAL;
}
-
if (ap) {
- set_mode_by_netdev(wl, ndev, mode);
+ wl_set_mode_by_netdev(wl, ndev, mode);
if (wl->p2p_supported && wl->p2p->vif_created) {
WL_DBG(("p2p_vif_created (%d) p2p_on (%d)\n", wl->p2p->vif_created,
- p2p_on(wl)));
- chspec = wf_chspec_aton(WL_P2P_TEMP_CHAN);
+ p2p_on(wl)));
+ wldev_iovar_setint(ndev, "mpc", 0);
+ wl_notify_escan_complete(wl, ndev, true, true);
+
+ /* In concurrency case, STA may be already associated in a particular
+ * channel. so retrieve the current channel of primary interface and
+ * then start the virtual interface on that.
+ */
+ chspec = wl_cfg80211_get_shared_freq(wiphy);
+
wlif_type = ap ? WL_P2P_IF_GO : WL_P2P_IF_CLIENT;
WL_ERR(("%s : ap (%d), infra (%d), iftype: (%d)\n",
ndev->name, ap, infra, type));
wl_set_p2p_status(wl, IF_CHANGING);
wl_clr_p2p_status(wl, IF_CHANGED);
err = wl_cfgp2p_ifchange(wl, &wl->p2p->int_addr, htod32(wlif_type), chspec);
- timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
+ timeout = wait_event_interruptible_timeout(wl->netif_change_event,
(wl_get_p2p_status(wl, IF_CHANGED) == true),
msecs_to_jiffies(MAX_WAIT_TIME));
- set_mode_by_netdev(wl, ndev, mode);
+ wl_set_mode_by_netdev(wl, ndev, mode);
wl_clr_p2p_status(wl, IF_CHANGING);
wl_clr_p2p_status(wl, IF_CHANGED);
} else if (ndev == wl_to_prmry_ndev(wl) &&
- !wl_get_drv_status(wl, AP_CREATED)) {
- wl_set_drv_status(wl, AP_CREATING);
+ !wl_get_drv_status(wl, AP_CREATED, ndev)) {
+ wl_set_drv_status(wl, AP_CREATING, ndev);
if (!wl->ap_info &&
!(wl->ap_info = kzalloc(sizeof(struct ap_info), GFP_KERNEL))) {
WL_ERR(("struct ap_saved_ie allocation failed\n"));
@@ -1027,15 +1051,16 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
s32
wl_cfg80211_notify_ifadd(struct net_device *ndev, s32 idx, s32 bssidx,
-int (*_net_attach)(dhd_pub_t *dhdp, int ifidx))
+ void* _net_attach)
{
struct wl_priv *wl = wlcfg_drv_priv;
s32 ret = BCME_OK;
+ WL_DBG(("Enter"));
if (!ndev) {
WL_ERR(("net is NULL\n"));
return 0;
}
- if (wl->p2p_supported) {
+ if (wl->p2p_supported && wl_get_p2p_status(wl, IF_ADD)) {
WL_DBG(("IF_ADD event called from dongle, old interface name: %s,"
"new name: %s\n", ndev->name, wl->p2p->vir_ifname));
/* Assign the net device to CONNECT BSSCFG */
@@ -1046,13 +1071,26 @@ int (*_net_attach)(dhd_pub_t *dhdp, int ifidx))
ndev->ifindex = idx;
wl_clr_p2p_status(wl, IF_ADD);
- wake_up_interruptible(&wl->dongle_event_wait);
+ wake_up_interruptible(&wl->netif_change_event);
+ } else {
+ ret = BCME_NOTREADY;
}
return ret;
}
s32
-wl_cfg80211_notify_ifdel(struct net_device *ndev)
+wl_cfg80211_notify_ifdel(void)
+{
+ struct wl_priv *wl = wlcfg_drv_priv;
+
+ WL_DBG(("Enter \n"));
+ wl_clr_p2p_status(wl, IF_DELETING);
+
+ return 0;
+}
+
+s32
+wl_cfg80211_ifdel_ops(struct net_device *ndev)
{
struct wl_priv *wl = wlcfg_drv_priv;
bool rollback_lock = false;
@@ -1063,8 +1101,10 @@ wl_cfg80211_notify_ifdel(struct net_device *ndev)
return 0;
}
- if (p2p_is_on(wl) && wl->p2p->vif_created) {
- if (wl->scan_request) {
+ if (p2p_is_on(wl) && wl->p2p->vif_created &&
+ wl_get_p2p_status(wl, IF_DELETING)) {
+ if (wl->scan_request &&
+ (wl->escan_info.ndev == ndev)) {
/* Abort any pending scan requests */
wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
if (!rtnl_is_locked()) {
@@ -1072,7 +1112,7 @@ wl_cfg80211_notify_ifdel(struct net_device *ndev)
rollback_lock = true;
}
WL_DBG(("ESCAN COMPLETED\n"));
- wl_notify_escan_complete(wl, true);
+ wl_notify_escan_complete(wl, ndev, true, false);
if (rollback_lock)
rtnl_unlock();
}
@@ -1086,12 +1126,12 @@ wl_cfg80211_notify_ifdel(struct net_device *ndev)
wl->p2p->vif_created = false;
wl_cfgp2p_clear_management_ie(wl,
index);
- wl_clr_p2p_status(wl, IF_DELETING);
WL_DBG(("index : %d\n", index));
}
+
/* Wake up any waiting thread */
- wake_up_interruptible(&wl->dongle_event_wait);
+ wake_up_interruptible(&wl->netif_change_event);
return 0;
}
@@ -1123,15 +1163,15 @@ wl_cfg80211_notify_ifchange(void)
struct wl_priv *wl = wlcfg_drv_priv;
if (wl_get_p2p_status(wl, IF_CHANGING)) {
wl_set_p2p_status(wl, IF_CHANGED);
- wake_up_interruptible(&wl->dongle_event_wait);
+ wake_up_interruptible(&wl->netif_change_event);
}
return 0;
}
static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_request *request)
{
- u32 n_ssids = request->n_ssids;
- u32 n_channels = request->n_channels;
+ u32 n_ssids;
+ u32 n_channels;
u16 channel;
chanspec_t chanspec;
s32 i, offset;
@@ -1160,6 +1200,13 @@ static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_req
params->passive_time = htod32(params->passive_time);
params->home_time = htod32(params->home_time);
+ /* if request is null just exit so it will be all channel broadcast scan */
+ if (!request)
+ return;
+
+ n_ssids = request->n_ssids;
+ n_channels = request->n_channels;
+
/* Copy channel array if applicable */
WL_SCAN(("### List of channelspecs to scan ###\n"));
if (n_channels > 0) {
@@ -1186,7 +1233,7 @@ static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_req
params->channel_list[i] &= WL_CHANSPEC_CHAN_MASK;
params->channel_list[i] |= chanspec;
WL_SCAN(("Chan : %d, Channel spec: %x \n",
- channel, params->channel_list[i]));
+ channel, params->channel_list[i]));
params->channel_list[i] = htod16(params->channel_list[i]);
}
} else {
@@ -1248,8 +1295,7 @@ wl_run_iscan(struct wl_iscan_ctrl *iscan, struct cfg80211_scan_request *request,
return -ENOMEM;
}
- if (request != NULL)
- wl_scan_prep(&params->params, request);
+ wl_scan_prep(&params->params, request);
params->version = htod32(ISCAN_REQ_VERSION);
params->action = htod16(action);
@@ -1261,7 +1307,7 @@ wl_run_iscan(struct wl_iscan_ctrl *iscan, struct cfg80211_scan_request *request,
goto done;
}
err = wldev_iovar_setbuf(iscan->dev, "iscan", params, params_size,
- iscan->ioctl_buf, WLC_IOCTL_MEDLEN);
+ iscan->ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
if (unlikely(err)) {
if (err == -EBUSY) {
WL_ERR(("system busy : iscan canceled\n"));
@@ -1299,6 +1345,25 @@ static s32 wl_do_iscan(struct wl_priv *wl, struct cfg80211_scan_request *request
}
static s32
+wl_get_valid_channels(struct net_device *ndev, u8 *valid_chan_list, s32 size)
+{
+ wl_uint32_list_t *list;
+ s32 err = BCME_OK;
+ if (valid_chan_list == NULL || size <= 0)
+ return -ENOMEM;
+
+ memset(valid_chan_list, 0, size);
+ list = (wl_uint32_list_t *)(void *) valid_chan_list;
+ list->count = htod32(WL_NUMCHANNELS);
+ err = wldev_ioctl(ndev, WLC_GET_VALID_CHANNELS, valid_chan_list, size, false);
+ if (err != 0) {
+ WL_ERR(("get channels failed with %d\n", err));
+ }
+
+ return err;
+}
+
+static s32
wl_run_escan(struct wl_priv *wl, struct net_device *ndev,
struct cfg80211_scan_request *request, uint16 action)
{
@@ -1306,12 +1371,16 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev,
u32 n_channels;
u32 n_ssids;
s32 params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_escan_params_t, params));
- wl_escan_params_t *params;
+ wl_escan_params_t *params = NULL;
struct cfg80211_scan_request *scan_request = wl->scan_request;
+ u8 chan_buf[sizeof(u32)*(WL_NUMCHANNELS + 1)];
u32 num_chans = 0;
+ s32 channel;
+ s32 n_valid_chan;
s32 search_state = WL_P2P_DISC_ST_SCAN;
- u32 i;
+ u32 i, j, n_nodfs = 0;
u16 *default_chan_list = NULL;
+ wl_uint32_list_t *list;
struct net_device *dev = NULL;
WL_DBG(("Enter \n"));
@@ -1340,8 +1409,7 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev,
goto exit;
}
- if (request != NULL)
- wl_scan_prep(&params->params, request);
+ wl_scan_prep(&params->params, request);
params->version = htod32(ESCAN_REQ_VERSION);
params->action = htod16(action);
params->sync_id = htod16(0x1234);
@@ -1352,13 +1420,15 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev,
goto exit;
}
err = wldev_iovar_setbuf(ndev, "escan", params, params_size,
- wl->escan_ioctl_buf, WLC_IOCTL_MEDLEN);
+ wl->escan_ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
if (unlikely(err))
WL_ERR((" Escan set error (%d)\n", err));
kfree(params);
}
- else if (p2p_on(wl) && p2p_scan(wl)) {
+ else if (p2p_is_on(wl) && p2p_scan(wl)) {
/* P2P SCAN TRIGGER */
+ s32 _freq = 0;
+ n_nodfs = 0;
if (scan_request && scan_request->n_channels) {
num_chans = scan_request->n_channels;
WL_SCAN((" chann number : %d\n", num_chans));
@@ -1369,11 +1439,26 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev,
err = -ENOMEM;
goto exit;
}
- for (i = 0; i < num_chans; i++)
- {
- default_chan_list[i] =
- ieee80211_frequency_to_channel(
- scan_request->channels[i]->center_freq);
+ if (!wl_get_valid_channels(ndev, chan_buf, sizeof(chan_buf))) {
+ list = (wl_uint32_list_t *) chan_buf;
+ n_valid_chan = dtoh32(list->count);
+ for (i = 0; i < num_chans; i++)
+ {
+ _freq = scan_request->channels[i]->center_freq;
+ channel = ieee80211_frequency_to_channel(_freq);
+ /* remove DFS channels */
+ if (channel < 52 || channel > 140) {
+ for (j = 0; j < n_valid_chan; j++) {
+ /* allows only supported channel on
+ * current reguatory
+ */
+ if (channel == (dtoh32(list->element[j])))
+ default_chan_list[n_nodfs++] =
+ channel;
+ }
+ }
+
+ }
}
if (num_chans == 3 && (
(default_chan_list[0] == SOCIAL_CHAN_1) &&
@@ -1383,12 +1468,15 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev,
search_state = WL_P2P_DISC_ST_SEARCH;
WL_INFO(("P2P SEARCH PHASE START \n"));
} else if ((dev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION)) &&
- (get_mode_by_netdev(wl, dev) == WL_MODE_AP)) {
+ (wl_get_mode_by_netdev(wl, dev) == WL_MODE_AP)) {
/* If you are already a GO, then do SEARCH only */
WL_INFO(("Already a GO. Do SEARCH Only"));
search_state = WL_P2P_DISC_ST_SEARCH;
+ num_chans = n_nodfs;
+
} else {
WL_INFO(("P2P SCAN STATE START \n"));
+ num_chans = n_nodfs;
}
}
@@ -1413,7 +1501,7 @@ wl_do_escan(struct wl_priv *wl, struct wiphy *wiphy, struct net_device *ndev,
s32 passive_scan;
wl_scan_results_t *results;
WL_SCAN(("Enter \n"));
-
+ wl->escan_info.ndev = ndev;
wl->escan_info.wiphy = wiphy;
wl->escan_info.escan_state = WL_ESCAN_STATE_SCANING;
passive_scan = wl->active_scan ? 0 : 1;
@@ -1440,36 +1528,41 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
struct wl_priv *wl = wiphy_priv(wiphy);
struct cfg80211_ssid *ssids;
struct wl_scan_req *sr = wl_to_sr(wl);
+ struct ether_addr primary_mac;
wpa_ie_fixed_t *wps_ie;
s32 passive_scan;
bool iscan_req;
- bool escan_req;
- bool spec_scan;
+ bool escan_req = false;
bool p2p_ssid;
s32 err = 0;
s32 i;
u32 wpsie_len = 0;
u8 wpsie[IE_MAX_LEN];
+ /* If scan req comes for p2p0, send it over primary I/F
+ * Scan results will be delivered corresponding to cfg80211_scan_request
+ */
+ if (ndev == wl->p2p_net) {
+ ndev = wl_to_prmry_ndev(wl);
+ }
+
WL_DBG(("Enter wiphy (%p)\n", wiphy));
- if (unlikely(wl_get_drv_status(wl, SCANNING))) {
- WL_ERR(("Scanning already : status (%d)\n", (int)wl->status));
+ if (wl_get_drv_status_all(wl, SCANNING)) {
+ WL_ERR(("Scanning already\n"));
return -EAGAIN;
}
- if (unlikely(wl_get_drv_status(wl, SCAN_ABORTING))) {
- WL_ERR(("Scanning being aborted : status (%d)\n",
- (int)wl->status));
+ if (wl_get_drv_status(wl, SCAN_ABORTING, ndev)) {
+ WL_ERR(("Scanning being aborted\n"));
return -EAGAIN;
}
- if (request->n_ssids > WL_SCAN_PARAMS_SSID_MAX) {
- WL_ERR(("n_ssids > WL_SCAN_PARAMS_SSID_MAX\n"));
+ if (request && request->n_ssids > WL_SCAN_PARAMS_SSID_MAX) {
+ WL_ERR(("request null or n_ssids > WL_SCAN_PARAMS_SSID_MAX\n"));
return -EOPNOTSUPP;
}
/* Arm scan timeout timer */
mod_timer(&wl->scan_timeout, jiffies + WL_SCAN_TIMER_INTERVAL_MS * HZ / 1000);
iscan_req = false;
- spec_scan = false;
if (request) { /* scan bss */
ssids = request->ssids;
if (wl->iscan_on && (!ssids || !ssids->ssid_len || request->n_ssids != 1)) {
@@ -1490,6 +1583,9 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
/* p2p on at the first time */
p2p_on(wl) = true;
wl_cfgp2p_set_firm_p2p(wl);
+ get_primary_mac(wl, &primary_mac);
+ wl_cfgp2p_generate_bss_mac(&primary_mac,
+ &wl->p2p->dev_addr, &wl->p2p->int_addr);
}
p2p_scan(wl) = true;
}
@@ -1543,7 +1639,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
ssids = this_ssid;
}
wl->scan_request = request;
- wl_set_drv_status(wl, SCANNING);
+ wl_set_drv_status(wl, SCANNING, ndev);
if (iscan_req) {
err = wl_do_iscan(wl, request);
if (likely(!err))
@@ -1578,7 +1674,6 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
sr->ssid.SSID_len = htod32(sr->ssid.SSID_len);
WL_SCAN(("Specific scan ssid=\"%s\" len=%d\n",
sr->ssid.SSID, sr->ssid.SSID_len));
- spec_scan = true;
} else {
WL_SCAN(("Broadcast scan\n"));
}
@@ -1606,7 +1701,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
return 0;
scan_out:
- wl_clr_drv_status(wl, SCANNING);
+ wl_clr_drv_status(wl, SCANNING, ndev);
wl->scan_request = NULL;
return err;
}
@@ -1630,52 +1725,11 @@ wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
return err;
}
-static s32 wl_dev_intvar_set(struct net_device *dev, s8 *name, s32 val)
-{
- s8 buf[WLC_IOCTL_SMLEN];
- u32 len;
- s32 err = 0;
-
- val = htod32(val);
- len = bcm_mkiovar(name, (char *)(&val), sizeof(val), buf, sizeof(buf));
- BUG_ON(unlikely(!len));
-
- err = wldev_ioctl(dev, WLC_SET_VAR, buf, len, false);
- if (unlikely(err)) {
- WL_ERR(("error (%d)\n", err));
- }
-
- return err;
-}
-
-static s32
-wl_dev_intvar_get(struct net_device *dev, s8 *name, s32 *retval)
-{
- union {
- s8 buf[WLC_IOCTL_SMLEN];
- s32 val;
- } var;
- u32 len;
- u32 data_null;
- s32 err = 0;
-
- len = bcm_mkiovar(name, (char *)(&data_null), 0,
- (char *)(&var), sizeof(var.buf));
- BUG_ON(unlikely(!len));
- err = wldev_ioctl(dev, WLC_GET_VAR, &var, len, false);
- if (unlikely(err)) {
- WL_ERR(("error (%d)\n", err));
- }
- *retval = dtoh32(var.val);
-
- return err;
-}
-
static s32 wl_set_rts(struct net_device *dev, u32 rts_threshold)
{
s32 err = 0;
- err = wl_dev_intvar_set(dev, "rtsthresh", rts_threshold);
+ err = wldev_iovar_setint(dev, "rtsthresh", rts_threshold);
if (unlikely(err)) {
WL_ERR(("Error (%d)\n", err));
return err;
@@ -1687,7 +1741,7 @@ static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold)
{
s32 err = 0;
- err = wl_dev_intvar_set(dev, "fragthresh", frag_threshold);
+ err = wldev_iovar_setint_bsscfg(dev, "fragthresh", frag_threshold, 0);
if (unlikely(err)) {
WL_ERR(("Error (%d)\n", err));
return err;
@@ -1716,6 +1770,7 @@ static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
s32 err = 0;
CHECK_SYS_UP(wl);
+ WL_DBG(("Enter\n"));
if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
(wl->conf->rts_threshold != wiphy->rts_threshold)) {
wl->conf->rts_threshold = wiphy->rts_threshold;
@@ -1745,7 +1800,6 @@ static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
return err;
}
}
-
return err;
}
@@ -1862,7 +1916,7 @@ wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme)
WL_ERR(("set wpa_auth failed (%d)\n", err));
return err;
}
- sec = wl_read_prof(wl, WL_PROF_SEC);
+ sec = wl_read_prof(wl, dev, WL_PROF_SEC);
sec->wpa_versions = sme->crypto.wpa_versions;
return err;
}
@@ -1877,21 +1931,21 @@ wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme)
s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
switch (sme->auth_type) {
case NL80211_AUTHTYPE_OPEN_SYSTEM:
- val = 0;
+ val = WL_AUTH_OPEN_SYSTEM;
WL_DBG(("open system\n"));
break;
case NL80211_AUTHTYPE_SHARED_KEY:
- val = 1;
+ val = WL_AUTH_SHARED_KEY;
WL_DBG(("shared key\n"));
break;
case NL80211_AUTHTYPE_AUTOMATIC:
- val = 2;
+ val = WL_AUTH_OPEN_SHARED;
WL_DBG(("automatic\n"));
break;
case NL80211_AUTHTYPE_NETWORK_EAP:
WL_DBG(("network eap\n"));
default:
- val = 2;
+ val = WL_AUTH_OPEN_SHARED;
WL_ERR(("invalid auth type (%d)\n", sme->auth_type));
break;
}
@@ -1901,7 +1955,7 @@ wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme)
WL_ERR(("set auth failed (%d)\n", err));
return err;
}
- sec = wl_read_prof(wl, WL_PROF_SEC);
+ sec = wl_read_prof(wl, dev, WL_PROF_SEC);
sec->auth_type = sme->auth_type;
return err;
}
@@ -1962,7 +2016,11 @@ wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme)
WL_DBG(("pval (%d) gval (%d)\n", pval, gval));
if (is_wps_conn(sme)) {
- err = wldev_iovar_setint_bsscfg(dev, "wsec", 4, bssidx);
+ if (sme->privacy)
+ err = wldev_iovar_setint_bsscfg(dev, "wsec", 4, bssidx);
+ else
+ /* WPS-2.0 allowes no security */
+ err = wldev_iovar_setint_bsscfg(dev, "wsec", 0, bssidx);
} else {
WL_DBG((" NO, is_wps_conn, Set pval | gval to WSEC"));
err = wldev_iovar_setint_bsscfg(dev, "wsec",
@@ -1973,7 +2031,7 @@ wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme)
return err;
}
- sec = wl_read_prof(wl, WL_PROF_SEC);
+ sec = wl_read_prof(wl, dev, WL_PROF_SEC);
sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
sec->cipher_group = sme->crypto.cipher_group;
@@ -1990,7 +2048,7 @@ wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme)
s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
if (sme->crypto.n_akm_suites) {
- err = wl_dev_intvar_get(dev, "wpa_auth", &val);
+ err = wldev_iovar_getint(dev, "wpa_auth", &val);
if (unlikely(err)) {
WL_ERR(("could not get wpa_auth (%d)\n", err));
return err;
@@ -2030,7 +2088,7 @@ wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme)
return err;
}
}
- sec = wl_read_prof(wl, WL_PROF_SEC);
+ sec = wl_read_prof(wl, dev, WL_PROF_SEC);
sec->wpa_auth = sme->crypto.akm_suites[0];
return err;
@@ -2049,13 +2107,14 @@ wl_set_set_sharedkey(struct net_device *dev,
WL_DBG(("key len (%d)\n", sme->key_len));
if (sme->key_len) {
- sec = wl_read_prof(wl, WL_PROF_SEC);
+ sec = wl_read_prof(wl, dev, WL_PROF_SEC);
WL_DBG(("wpa_versions 0x%x cipher_pairwise 0x%x\n",
sec->wpa_versions, sec->cipher_pairwise));
if (!(sec->wpa_versions & (NL80211_WPA_VERSION_1 |
NL80211_WPA_VERSION_2)) &&
(sec->cipher_pairwise & (WLAN_CIPHER_SUITE_WEP40 |
- WLAN_CIPHER_SUITE_WEP104))) {
+ WLAN_CIPHER_SUITE_WEP104)))
+ {
memset(&key, 0, sizeof(key));
key.len = (u32) sme->key_len;
key.index = (u32) sme->key_idx;
@@ -2083,14 +2142,14 @@ wl_set_set_sharedkey(struct net_device *dev,
WL_DBG(("key \"%s\"\n", key.data));
swap_key_from_BE(&key);
err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
- ioctlbuf, sizeof(ioctlbuf), bssidx);
+ wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync);
if (unlikely(err)) {
WL_ERR(("WLC_SET_KEY error (%d)\n", err));
return err;
}
- if (sec->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) {
+ if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
WL_DBG(("set auth_type to shared key\n"));
- val = 1; /* shared key */
+ val = WL_AUTH_SHARED_KEY; /* shared key */
err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx);
if (unlikely(err)) {
WL_ERR(("set auth failed (%d)\n", err));
@@ -2129,15 +2188,15 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
* Cancel ongoing scan to sync up with sme state machine of cfg80211.
*/
if (wl->scan_request) {
- wl_cfg80211_scan_abort(wl, dev);
+ wl_notify_escan_complete(wl, dev, true, true);
}
/* Clean BSSID */
bzero(&bssid, sizeof(bssid));
- wl_update_prof(wl, NULL, (void *)&bssid, WL_PROF_BSSID);
+ wl_update_prof(wl, dev, NULL, (void *)&bssid, WL_PROF_BSSID);
if (IS_P2P_SSID(sme->ssid) && (dev != wl_to_prmry_ndev(wl))) {
/* we only allow to connect using virtual interface in case of P2P */
- if (p2p_on(wl) && is_wps_conn(sme)) {
+ if (p2p_is_on(wl) && is_wps_conn(sme)) {
WL_DBG(("ASSOC1 p2p index : %d sme->ie_len %d\n",
wl_cfgp2p_find_idx(wl, dev), sme->ie_len));
/* Have to apply WPS IE + P2P IE in assoc req frame */
@@ -2148,7 +2207,7 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie_len);
wl_cfgp2p_set_management_ie(wl, dev, wl_cfgp2p_find_idx(wl, dev),
VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len);
- } else if (p2p_on(wl) && (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)) {
+ } else if (p2p_is_on(wl) && (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)) {
/* This is the connect req after WPS is done [credentials exchanged]
* currently identified with WPA_VERSION_2 .
* Update the previously set IEs with
@@ -2158,6 +2217,8 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
WL_DBG(("ASSOC2 p2p index : %d sme->ie_len %d\n",
wl_cfgp2p_find_idx(wl, dev), sme->ie_len));
wl_cfgp2p_set_management_ie(wl, dev, wl_cfgp2p_find_idx(wl, dev),
+ VNDR_IE_PRBREQ_FLAG, sme->ie, sme->ie_len);
+ wl_cfgp2p_set_management_ie(wl, dev, wl_cfgp2p_find_idx(wl, dev),
VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len);
}
@@ -2177,10 +2238,10 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
wpaie_len = (wpa_ie != NULL) ? wpa_ie->length : wpa2_ie->len;
wpaie_len += WPA_RSN_IE_TAG_FIXED_LEN;
wldev_iovar_setbuf(dev, "wpaie", wpaie, wpaie_len,
- ioctlbuf, sizeof(ioctlbuf));
+ wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync);
} else {
wldev_iovar_setbuf(dev, "wpaie", NULL, 0,
- ioctlbuf, sizeof(ioctlbuf));
+ wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync);
}
/* find the WPSIE */
@@ -2249,7 +2310,7 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
ext_join_params = (wl_extjoin_params_t*)kzalloc(join_params_size, GFP_KERNEL);
if (ext_join_params == NULL) {
err = -ENOMEM;
- wl_clr_drv_status(wl, CONNECTING);
+ wl_clr_drv_status(wl, CONNECTING, dev);
goto exit;
}
ext_join_params->ssid.SSID_len = min(sizeof(ext_join_params->ssid.SSID), sme->ssid_len);
@@ -2258,12 +2319,13 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
/* Set up join scan parameters */
ext_join_params->scan.scan_type = -1;
ext_join_params->scan.nprobes = 2;
- /* increate dwell time to receive probe response
- * from target AP at a noisy air
+ /* increate dwell time to receive probe response or detect Beacon
+ * from target AP at a noisy air only during connect command
*/
- ext_join_params->scan.active_time = 150;
- ext_join_params->scan.passive_time = 300;
+ ext_join_params->scan.active_time = WL_SCAN_ACTIVE_TIME*3;
+ ext_join_params->scan.passive_time = WL_SCAN_PASSIVE_TIME*3;
ext_join_params->scan.home_time = -1;
+
if (sme->bssid)
memcpy(&ext_join_params->assoc.bssid, sme->bssid, ETH_ALEN);
else
@@ -2288,12 +2350,12 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
WL_INFO(("ssid \"%s\", len (%d)\n", ext_join_params->ssid.SSID,
ext_join_params->ssid.SSID_len));
}
- wl_set_drv_status(wl, CONNECTING);
- err = wldev_iovar_setbuf_bsscfg(dev, "join", ext_join_params, join_params_size, ioctlbuf,
- sizeof(ioctlbuf), wl_cfgp2p_find_idx(wl, dev));
+ wl_set_drv_status(wl, CONNECTING, dev);
+ err = wldev_iovar_setbuf_bsscfg(dev, "join", ext_join_params, join_params_size,
+ wl->ioctl_buf, WLC_IOCTL_MAXLEN, wl_cfgp2p_find_idx(wl, dev), &wl->ioctl_buf_sync);
kfree(ext_join_params);
if (err) {
- wl_clr_drv_status(wl, CONNECTING);
+ wl_clr_drv_status(wl, CONNECTING, dev);
if (err == BCME_UNSUPPORTED) {
WL_DBG(("join iovar is not supported\n"));
goto set_ssid;
@@ -2309,7 +2371,7 @@ set_ssid:
join_params.ssid.SSID_len = min(sizeof(join_params.ssid.SSID), sme->ssid_len);
memcpy(&join_params.ssid.SSID, sme->ssid, join_params.ssid.SSID_len);
join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len);
- wl_update_prof(wl, NULL, &join_params.ssid, WL_PROF_SSID);
+ wl_update_prof(wl, dev, NULL, &join_params.ssid, WL_PROF_SSID);
if (sme->bssid)
memcpy(&join_params.params.bssid, sme->bssid, ETH_ALEN);
else
@@ -2322,11 +2384,11 @@ set_ssid:
WL_INFO(("ssid \"%s\", len (%d)\n", join_params.ssid.SSID,
join_params.ssid.SSID_len));
}
- wl_set_drv_status(wl, CONNECTING);
+ wl_set_drv_status(wl, CONNECTING, dev);
err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size, true);
if (err) {
WL_ERR(("error (%d)\n", err));
- wl_clr_drv_status(wl, CONNECTING);
+ wl_clr_drv_status(wl, CONNECTING, dev);
}
exit:
return err;
@@ -2343,23 +2405,23 @@ wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
u8 *curbssid;
WL_ERR(("Reason %d\n", reason_code));
CHECK_SYS_UP(wl);
- act = *(bool *) wl_read_prof(wl, WL_PROF_ACT);
- curbssid = wl_read_prof(wl, WL_PROF_BSSID);
- if (likely(act)) {
+ act = *(bool *) wl_read_prof(wl, dev, WL_PROF_ACT);
+ curbssid = wl_read_prof(wl, dev, WL_PROF_BSSID);
+ if (act) {
/*
* Cancel ongoing scan to sync up with sme state machine of cfg80211.
*/
if (wl->scan_request) {
- wl_cfg80211_scan_abort(wl, dev);
+ wl_notify_escan_complete(wl, dev, true, true);
}
- wl_set_drv_status(wl, DISCONNECTING);
+ wl_set_drv_status(wl, DISCONNECTING, dev);
scbval.val = reason_code;
memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
scbval.val = htod32(scbval.val);
err = wldev_ioctl(dev, WLC_DISASSOC, &scbval,
sizeof(scb_val_t), true);
if (unlikely(err)) {
- wl_clr_drv_status(wl, DISCONNECTING);
+ wl_clr_drv_status(wl, DISCONNECTING, dev);
WL_ERR(("error (%d)\n", err));
return err;
}
@@ -2409,7 +2471,7 @@ wl_cfg80211_set_tx_power(struct wiphy *wiphy,
txpwrmw = 0xffff;
else
txpwrmw = (u16) dbm;
- err = wl_dev_intvar_set(ndev, "qtxpower",
+ err = wldev_iovar_setint(ndev, "qtxpower",
(s32) (bcm_mw_to_qdbm(txpwrmw)));
if (unlikely(err)) {
WL_ERR(("qtxpower error (%d)\n", err));
@@ -2429,7 +2491,7 @@ static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm)
s32 err = 0;
CHECK_SYS_UP(wl);
- err = wl_dev_intvar_get(ndev, "qtxpower", &txpwrdbm);
+ err = wldev_iovar_getint(ndev, "qtxpower", &txpwrdbm);
if (unlikely(err)) {
WL_ERR(("error (%d)\n", err));
return err;
@@ -2478,7 +2540,7 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
struct wl_wsec_key key;
s32 err = 0;
s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
- s32 mode = get_mode_by_netdev(wl, dev);
+ s32 mode = wl_get_mode_by_netdev(wl, dev);
memset(&key, 0, sizeof(key));
key.index = (u32) key_idx;
@@ -2490,8 +2552,8 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
if (key.len == 0) {
/* key delete */
swap_key_from_BE(&key);
- wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), ioctlbuf,
- sizeof(ioctlbuf), bssidx);
+ wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
+ wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync);
if (unlikely(err)) {
WL_ERR(("key delete error (%d)\n", err));
return err;
@@ -2549,11 +2611,8 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
return -EINVAL;
}
swap_key_from_BE(&key);
-#ifdef CONFIG_WIRELESS_EXT
- dhd_wait_pend8021x(dev);
-#endif
- wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), ioctlbuf,
- sizeof(ioctlbuf), bssidx);
+ wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
+ wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync);
if (unlikely(err)) {
WL_ERR(("WLC_SET_KEY error (%d)\n", err));
return err;
@@ -2574,7 +2633,7 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
u8 keybuf[8];
s32 bssidx = 0;
struct wl_priv *wl = wiphy_priv(wiphy);
- s32 mode = get_mode_by_netdev(wl, dev);
+ s32 mode = wl_get_mode_by_netdev(wl, dev);
WL_DBG(("key index (%d)\n", key_idx));
CHECK_SYS_UP(wl);
@@ -2635,8 +2694,8 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
/* Set the new key/index */
swap_key_from_BE(&key);
- err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), ioctlbuf,
- sizeof(ioctlbuf), bssidx);
+ err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), wl->ioctl_buf,
+ WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync);
if (unlikely(err)) {
WL_ERR(("WLC_SET_KEY error (%d)\n", err));
return err;
@@ -2672,15 +2731,15 @@ wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
CHECK_SYS_UP(wl);
memset(&key, 0, sizeof(key));
- key.index = (u32) key_idx;
key.flags = WL_PRIMARY_KEY;
key.algo = CRYPTO_ALGO_OFF;
+ key.index = (u32) key_idx;
WL_DBG(("key index (%d)\n", key_idx));
/* Set the new key/index */
swap_key_from_BE(&key);
- wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), ioctlbuf,
- sizeof(ioctlbuf), bssidx);
+ wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), wl->ioctl_buf,
+ WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync);
if (unlikely(err)) {
if (err == -EINVAL) {
if (key.index >= DOT11_MAX_DEFAULT_KEYS) {
@@ -2724,7 +2783,7 @@ wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
}
switch (wsec & ~SES_OW_ENABLED) {
case WEP_ENABLED:
- sec = wl_read_prof(wl, WL_PROF_SEC);
+ sec = wl_read_prof(wl, dev, WL_PROF_SEC);
if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
params.cipher = WLAN_CIPHER_SUITE_WEP40;
WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
@@ -2774,15 +2833,15 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
CHECK_SYS_UP(wl);
- if (get_mode_by_netdev(wl, dev) == WL_MODE_AP) {
+ if (wl_get_mode_by_netdev(wl, dev) == WL_MODE_AP) {
err = wldev_iovar_getbuf(dev, "sta_info", (struct ether_addr *)mac,
- ETHER_ADDR_LEN, ioctlbuf, sizeof(ioctlbuf));
+ ETHER_ADDR_LEN, wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync);
if (err < 0) {
WL_ERR(("GET STA INFO failed, %d\n", err));
return err;
}
sinfo->filled = STATION_INFO_INACTIVE_TIME;
- sta = (sta_info_t *)ioctlbuf;
+ sta = (sta_info_t *)wl->ioctl_buf;
sta->len = dtoh16(sta->len);
sta->cap = dtoh16(sta->cap);
sta->flags = dtoh32(sta->flags);
@@ -2798,50 +2857,48 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
bcm_ether_ntoa((const struct ether_addr *)mac, eabuf), sinfo->inactive_time,
sta->idle * 1000));
#endif
- } else if (get_mode_by_netdev(wl, dev) == WL_MODE_BSS) {
- u8 *curmacp = wl_read_prof(wl, WL_PROF_BSSID);
-
- if (!wl_get_drv_status(wl, CONNECTED) ||
- (dhd_is_associated(dhd, NULL) == FALSE)) {
- WL_ERR(("NOT assoc\n"));
- err = -ENODEV;
- goto get_station_err;
- }
- if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) {
- WL_ERR(("Wrong Mac address: "MACSTR" != "MACSTR"\n",
- MAC2STR(mac), MAC2STR(curmacp)));
- }
-
- /* Report the current tx rate */
- err = wldev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate), false);
- if (err) {
- WL_ERR(("Could not get rate (%d)\n", err));
- } else {
- rate = dtoh32(rate);
- sinfo->filled |= STATION_INFO_TX_BITRATE;
- sinfo->txrate.legacy = rate * 5;
- WL_DBG(("Rate %d Mbps\n", (rate / 2)));
- }
+ } else if (wl_get_mode_by_netdev(wl, dev) == WL_MODE_BSS) {
+ u8 *curmacp = wl_read_prof(wl, dev, WL_PROF_BSSID);
+ err = -ENODEV;
+ if (!wl_get_drv_status(wl, CONNECTED, dev) ||
+ (dhd_is_associated(dhd, NULL, &err) == FALSE)) {
+ WL_ERR(("NOT assoc: %d\n", err));
+ goto get_station_err;
+ }
+ if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) {
+ WL_ERR(("Wrong Mac address: "MACSTR" != "MACSTR"\n",
+ MAC2STR(mac), MAC2STR(curmacp)));
+ }
- memset(&scb_val, 0, sizeof(scb_val));
- scb_val.val = 0;
- err = wldev_ioctl(dev, WLC_GET_RSSI, &scb_val,
- sizeof(scb_val_t), false);
- if (err) {
- WL_ERR(("Could not get rssi (%d)\n", err));
- goto get_station_err;
- }
+ /* Report the current tx rate */
+ err = wldev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate), false);
+ if (err) {
+ WL_ERR(("Could not get rate (%d)\n", err));
+ } else {
+ rate = dtoh32(rate);
+ sinfo->filled |= STATION_INFO_TX_BITRATE;
+ sinfo->txrate.legacy = rate * 5;
+ WL_DBG(("Rate %d Mbps\n", (rate / 2)));
+ }
- rssi = dtoh32(scb_val.val);
- sinfo->filled |= STATION_INFO_SIGNAL;
- sinfo->signal = rssi;
- WL_DBG(("RSSI %d dBm\n", rssi));
+ memset(&scb_val, 0, sizeof(scb_val));
+ scb_val.val = 0;
+ err = wldev_ioctl(dev, WLC_GET_RSSI, &scb_val,
+ sizeof(scb_val_t), false);
+ if (err) {
+ WL_ERR(("Could not get rssi (%d)\n", err));
+ goto get_station_err;
+ }
+ rssi = dtoh32(scb_val.val);
+ sinfo->filled |= STATION_INFO_SIGNAL;
+ sinfo->signal = rssi;
+ WL_DBG(("RSSI %d dBm\n", rssi));
get_station_err:
- if (err) {
+ if (err && (err != -ETIMEDOUT) && (err != -EIO)) {
/* Disconnect due to zero BSSID or error to get RSSI */
- WL_ERR(("force cfg80211_disconnected\n"));
- wl_clr_drv_status(wl, CONNECTED);
+ WL_ERR(("force cfg80211_disconnected: %d\n", err));
+ wl_clr_drv_status(wl, CONNECTED, dev);
cfg80211_disconnected(dev, 0, NULL, 0, GFP_KERNEL);
wl_link_down(wl);
}
@@ -2859,14 +2916,14 @@ wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
struct wl_priv *wl = wiphy_priv(wiphy);
CHECK_SYS_UP(wl);
- pm = enabled ? PM_FAST : PM_OFF;
- /* Do not enable the power save after assoc if it is p2p interface */
- if (wl->p2p && wl->p2p->vif_created) {
- WL_DBG(("Do not enable the power save for p2p interfaces even after assoc\n"));
- pm = PM_OFF;
+
+ WL_DBG(("Enter : power save %s\n", (enabled ? "enable" : "disable")));
+ if (wl->p2p_net == dev) {
+ return err;
}
+
+ pm = enabled ? PM_FAST : PM_OFF;
pm = htod32(pm);
- WL_DBG(("power save %s\n", (pm ? "enabled" : "disabled")));
err = wldev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), true);
if (unlikely(err)) {
if (err == -ENODEV)
@@ -2875,6 +2932,7 @@ wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
WL_ERR(("error (%d)\n", err));
return err;
}
+ WL_DBG(("power save %s\n", (pm ? "enabled" : "disabled")));
return err;
}
@@ -2908,11 +2966,11 @@ static __used u32 wl_find_msb(u16 bit16)
static s32 wl_cfg80211_resume(struct wiphy *wiphy)
{
struct wl_priv *wl = wiphy_priv(wiphy);
+ struct net_device *ndev = wl_to_prmry_ndev(wl);
s32 err = 0;
- if (unlikely(!wl_get_drv_status(wl, READY))) {
- WL_INFO(("device is not ready : status (%d)\n",
- (int)wl->status));
+ if (unlikely(!wl_get_drv_status(wl, READY, ndev))) {
+ WL_INFO(("device is not ready\n"));
return 0;
}
@@ -2929,33 +2987,38 @@ static s32 wl_cfg80211_suspend(struct wiphy *wiphy)
{
#ifdef DHD_CLEAR_ON_SUSPEND
struct wl_priv *wl = wiphy_priv(wiphy);
+ struct net_info *iter, *next;
struct net_device *ndev = wl_to_prmry_ndev(wl);
unsigned long flags;
- if (unlikely(!wl_get_drv_status(wl, READY))) {
+ if (unlikely(!wl_get_drv_status(wl, READY, ndev))) {
WL_INFO(("device is not ready : status (%d)\n",
(int)wl->status));
return 0;
}
-
- wl_set_drv_status(wl, SCAN_ABORTING);
+ for_each_ndev(wl, iter, next)
+ wl_set_drv_status(wl, SCAN_ABORTING, iter->ndev);
wl_term_iscan(wl);
- flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
+ spin_lock_irqsave(&wl->cfgdrv_lock, flags);
if (wl->scan_request) {
cfg80211_scan_done(wl->scan_request, true);
wl->scan_request = NULL;
}
- wl_clr_drv_status(wl, SCANNING);
- wl_clr_drv_status(wl, SCAN_ABORTING);
- dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
- if (wl_get_drv_status(wl, CONNECTING)) {
- wl_bss_connect_done(wl, ndev, NULL, NULL, false);
+ for_each_ndev(wl, iter, next) {
+ wl_clr_drv_status(wl, SCANNING, iter->ndev);
+ wl_clr_drv_status(wl, SCAN_ABORTING, iter->ndev);
}
-#endif
+ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags);
+ for_each_ndev(wl, iter, next) {
+ if (wl_get_drv_status(wl, CONNECTING, iter->ndev)) {
+ wl_bss_connect_done(wl, iter->ndev, NULL, NULL, false);
+ }
+ }
+#endif /* DHD_CLEAR_ON_SUSPEND */
return 0;
}
-static __used s32
+static s32
wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list,
s32 err)
{
@@ -2963,10 +3026,13 @@ wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list,
struct wl_priv *wl = wlcfg_drv_priv;
struct net_device *primary_dev = wl_to_prmry_ndev(wl);
- /* Firmware is supporting pmk list only for STA interface i.e. primary interface
- * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init
- * Do we really need to support PMK cache in P2P in firmware?
- */
+ if (!pmk_list) {
+ printk("pmk_list is NULL\n");
+ return -EINVAL;
+ }
+ /* pmk list is supported only for STA interface i.e. primary interface
+ * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init
+ */
if (primary_dev != dev) {
WL_INFO(("Not supporting Flushing pmklist on virtual"
" interfaces than primary interface\n"));
@@ -2982,8 +3048,8 @@ wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list,
}
}
if (likely(!err)) {
- err = wl_dev_bufvar_set(dev, "pmkid_info", (char *)pmk_list,
- sizeof(*pmk_list));
+ err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmk_list,
+ sizeof(*pmk_list), wl->ioctl_buf, WLC_IOCTL_MAXLEN, NULL);
}
return err;
@@ -3084,7 +3150,7 @@ wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev)
}
-wl_scan_params_t *
+static wl_scan_params_t *
wl_cfg80211_scan_alloc_params(int channel, int nprobes, int *out_params_size)
{
wl_scan_params_t *params;
@@ -3116,47 +3182,12 @@ wl_cfg80211_scan_alloc_params(int channel, int nprobes, int *out_params_size)
/* Our scan params have 1 channel and 0 ssids */
params->channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) |
- (num_chans & WL_SCAN_PARAMS_COUNT_MASK));
+ (num_chans & WL_SCAN_PARAMS_COUNT_MASK));
*out_params_size = params_size; /* rtn size to the caller */
return params;
}
-s32
-wl_cfg80211_scan_abort(struct wl_priv *wl, struct net_device *ndev)
-{
- wl_scan_params_t *params = NULL;
- s32 params_size = 0;
- s32 err = BCME_OK;
- unsigned long flags;
-
- WL_DBG(("Enter\n"));
-
- /* Our scan params only need space for 1 channel and 0 ssids */
- params = wl_cfg80211_scan_alloc_params(-1, 0, &params_size);
- if (params == NULL) {
- WL_ERR(("scan params allocation failed \n"));
- err = -ENOMEM;
- } else {
- /* Do a scan abort to stop the driver's scan engine */
- err = wldev_ioctl(ndev, WLC_SCAN, params, params_size, true);
- if (err < 0) {
- WL_ERR(("scan abort failed \n"));
- }
- }
- del_timer_sync(&wl->scan_timeout);
- flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
- if (wl->scan_request) {
- cfg80211_scan_done(wl->scan_request, true);
- wl->scan_request = NULL;
- }
- wl_clr_drv_status(wl, SCANNING);
- dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
- if (params)
- kfree(params);
- return err;
-}
-
static s32
wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_channel * channel,
@@ -3164,36 +3195,48 @@ wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev,
unsigned int duration, u64 *cookie)
{
s32 target_channel;
+ u32 id;
+ struct ether_addr primary_mac;
+ struct net_device *ndev = NULL;
s32 err = BCME_OK;
struct wl_priv *wl = wiphy_priv(wiphy);
- dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
WL_DBG(("Enter, netdev_ifidx: %d \n", dev->ifindex));
- if (likely(wl_get_drv_status(wl, SCANNING))) {
- wl_cfg80211_scan_abort(wl, dev);
+
+ if (wl->p2p_net == dev) {
+ ndev = wl_to_prmry_ndev(wl);
+ } else {
+ ndev = dev;
}
+ if (wl_get_drv_status(wl, SCANNING, ndev)) {
+ wl_notify_escan_complete(wl, ndev, true, true);
+ }
target_channel = ieee80211_frequency_to_channel(channel->center_freq);
memcpy(&wl->remain_on_chan, channel, sizeof(struct ieee80211_channel));
wl->remain_on_chan_type = channel_type;
- wl->cache_cookie = *cookie;
+ id = ++wl->last_roc_id;
+ if (id == 0)
+ id = ++wl->last_roc_id;
+ *cookie = id;
cfg80211_ready_on_channel(dev, *cookie, channel,
channel_type, duration, GFP_KERNEL);
- if (!p2p_on(wl)) {
- wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr);
+ if (wl->p2p && !wl->p2p->on) {
+ get_primary_mac(wl, &primary_mac);
+ wl_cfgp2p_generate_bss_mac(&primary_mac, &wl->p2p->dev_addr, &wl->p2p->int_addr);
/* In case of p2p_listen command, supplicant send remain_on_channel
* without turning on P2P
*/
p2p_on(wl) = true;
- err = wl_cfgp2p_enable_discovery(wl, dev, NULL, 0);
+ err = wl_cfgp2p_enable_discovery(wl, ndev, NULL, 0);
if (unlikely(err)) {
goto exit;
}
}
- if (p2p_on(wl))
+ if (p2p_is_on(wl))
wl_cfgp2p_discover_listen(wl, target_channel, duration);
@@ -3211,39 +3254,143 @@ wl_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, struct net_device *dev
}
static s32
-wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
+wl_cfg80211_send_pending_tx_act_frm(struct wl_priv *wl)
+{
+ wl_af_params_t *tx_act_frm;
+ struct net_device *dev = wl->afx_hdl->dev;
+ if (!p2p_is_on(wl))
+ return -1;
+
+ if (dev == wl->p2p_net) {
+ dev = wl_to_prmry_ndev(wl);
+ }
+
+ tx_act_frm = wl->afx_hdl->pending_tx_act_frm;
+ WL_DBG(("Sending the action frame\n"));
+ wl->afx_hdl->pending_tx_act_frm = NULL;
+ if (tx_act_frm != NULL) {
+ /* Suspend P2P discovery's search-listen to prevent it from
+ * starting a scan or changing the channel.
+ */
+ wl_clr_drv_status(wl, SENDING_ACT_FRM, wl->afx_hdl->dev);
+ wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev);
+ wl_notify_escan_complete(wl, dev, true, true);
+ wl_cfgp2p_discover_enable_search(wl, false);
+ tx_act_frm->channel = wl->afx_hdl->peer_chan;
+ wl->afx_hdl->ack_recv = (wl_cfgp2p_tx_action_frame(wl, dev,
+ tx_act_frm, wl->afx_hdl->bssidx)) ? false : true;
+ }
+ return 0;
+}
+static void
+wl_cfg80211_afx_handler(struct work_struct *work)
+{
+
+ struct afx_hdl *afx_instance;
+ struct wl_priv *wl = wlcfg_drv_priv;
+ afx_instance = container_of(work, struct afx_hdl, work);
+ if (afx_instance != NULL) {
+ wl_cfgp2p_act_frm_search(wl, wl->afx_hdl->dev,
+ wl->afx_hdl->bssidx, 0);
+ }
+}
+
+static bool
+wl_cfg80211_send_at_common_channel(struct wl_priv *wl,
+ struct net_device *dev,
+ wl_af_params_t *af_params)
+{
+ WL_DBG((" enter ) \n"));
+ /* initialize afx_hdl */
+ wl->afx_hdl->pending_tx_act_frm = af_params;
+ wl->afx_hdl->bssidx = wl_cfgp2p_find_idx(wl, dev);
+ wl->afx_hdl->dev = dev;
+ wl->afx_hdl->retry = 0;
+ wl->afx_hdl->peer_chan = WL_INVALID;
+ wl->afx_hdl->ack_recv = false;
+ memcpy(wl->afx_hdl->pending_tx_dst_addr.octet,
+ af_params->action_frame.da.octet,
+ sizeof(wl->afx_hdl->pending_tx_dst_addr.octet));
+ /* Loop to wait until we have sent the pending tx action frame or the
+ * pending action frame tx is cancelled.
+ */
+ while ((wl->afx_hdl->retry < WL_CHANNEL_SYNC_RETRY) &&
+ (wl->afx_hdl->peer_chan == WL_INVALID)) {
+ wl_set_drv_status(wl, SENDING_ACT_FRM, dev);
+ wl_set_drv_status(wl, SCANNING, dev);
+ WL_DBG(("Scheduling the action frame for sending.. retry %d\n",
+ wl->afx_hdl->retry));
+ /* Do find_peer_for_action */
+ schedule_work(&wl->afx_hdl->work);
+ wait_for_completion(&wl->act_frm_scan);
+ wl->afx_hdl->retry++;
+ }
+ if (wl->afx_hdl->peer_chan != WL_INVALID)
+ wl_cfg80211_send_pending_tx_act_frm(wl);
+ else {
+ WL_ERR(("Couldn't find the peer after %d retries\n",
+ wl->afx_hdl->retry));
+ }
+ wl->afx_hdl->dev = NULL;
+ wl->afx_hdl->bssidx = WL_INVALID;
+ wl_clr_drv_status(wl, SENDING_ACT_FRM, dev);
+ if (wl->afx_hdl->ack_recv)
+ return true; /* ACK */
+ else
+ return false; /* NO ACK */
+}
+
+static s32
+wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev,
struct ieee80211_channel *channel, bool offchan,
enum nl80211_channel_type channel_type,
bool channel_type_valid, unsigned int wait,
- const u8* buf, size_t len, u64 *cookie)
+ const u8* buf, size_t len,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+ bool no_cck,
+#endif
+ u64 *cookie)
{
wl_action_frame_t *action_frame;
wl_af_params_t *af_params;
wifi_p2p_ie_t *p2p_ie;
wpa_ie_fixed_t *wps_ie;
+ wifi_wfd_ie_t *wfd_ie;
+ scb_val_t scb_val;
const struct ieee80211_mgmt *mgmt;
struct wl_priv *wl = wiphy_priv(wiphy);
- dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
+ struct net_device *dev = NULL;
s32 err = BCME_OK;
s32 bssidx = 0;
u32 p2pie_len = 0;
u32 wpsie_len = 0;
- u16 fc;
+ u32 wfdie_len = 0;
+ u32 id;
+ u32 retry = 0;
bool ack = false;
- wifi_p2p_pub_act_frame_t *act_frm;
+ wifi_p2p_pub_act_frame_t *act_frm = NULL;
+ wifi_p2p_action_frame_t *p2p_act_frm = NULL;
+ wifi_p2psd_gas_pub_act_frame_t *sd_act_frm = NULL;
+ s8 eabuf[ETHER_ADDR_STR_LEN];
+ int retry_cnt = 0;
+
WL_DBG(("Enter \n"));
+
+ if (ndev == wl->p2p_net) {
+ dev = wl_to_prmry_ndev(wl);
+ } else {
+ /* If TX req is for any valid ifidx. Use as is */
+ dev = ndev;
+ }
+
/* find bssidx based on ndev */
bssidx = wl_cfgp2p_find_idx(wl, dev);
- /* cookie generation */
- *cookie = (unsigned long) buf;
-
if (bssidx == -1) {
WL_ERR(("Can not find the bssidx for dev( %p )\n", dev));
return -ENODEV;
}
- if (wl->p2p_supported && p2p_on(wl)) {
- wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr);
+ if (p2p_is_on(wl)) {
/* Suspend P2P discovery search-listen to prevent it from changing the
* channel.
*/
@@ -3252,50 +3399,74 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
return -EFAULT;
}
}
-
- mgmt = (const struct ieee80211_mgmt *) buf;
- fc = mgmt->frame_control;
- if (fc != IEEE80211_STYPE_ACTION) {
- if (fc == IEEE80211_STYPE_PROBE_RESP) {
+ *cookie = 0;
+ id = wl->send_action_id++;
+ if (id == 0)
+ id = wl->send_action_id++;
+ *cookie = id;
+ mgmt = (const struct ieee80211_mgmt *)buf;
+ if (ieee80211_is_mgmt(mgmt->frame_control)) {
+ if (ieee80211_is_probe_resp(mgmt->frame_control)) {
s32 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
s32 ie_len = len - ie_offset;
if ((p2p_ie = wl_cfgp2p_find_p2pie((u8 *)(buf + ie_offset), ie_len))
!= NULL) {
/* Total length of P2P Information Element */
p2pie_len = p2p_ie->len + sizeof(p2p_ie->len) + sizeof(p2p_ie->id);
- /* Have to change p2p device address in dev_info attribute
- * because Supplicant use primary eth0 address
- */
- #ifdef ENABLE_DRIVER_CHANGE_IFADDR /* We are now doing this in supplicant */
- wl_cfg80211_change_ifaddr((u8 *)p2p_ie,
- &wl->p2p_dev_addr, P2P_SEID_DEV_INFO);
- #endif
+ }
+ if ((wfd_ie = wl_cfgp2p_find_wfdie((u8 *)(buf + ie_offset), ie_len))
+ != NULL) {
+ /* Total length of WFD Information Element */
+ wfdie_len = wfd_ie->len + sizeof(wfd_ie->len) + sizeof(wfd_ie->id);
}
if ((wps_ie = wl_cfgp2p_find_wpsie((u8 *)(buf + ie_offset), ie_len))
!= NULL) {
/* Order of Vendor IE is 1) WPS IE +
* 2) P2P IE created by supplicant
* So, it is ok to find start address of WPS IE
- * to save IEs to firmware
+ * to save IEs
*/
wpsie_len = wps_ie->length + sizeof(wps_ie->length) +
sizeof(wps_ie->tag);
wl_cfgp2p_set_management_ie(wl, dev, bssidx,
VNDR_IE_PRBRSP_FLAG,
- (u8 *)wps_ie, wpsie_len + p2pie_len);
+ (u8 *)wps_ie, wpsie_len + p2pie_len + wfdie_len);
}
+ cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, true, GFP_KERNEL);
+ goto exit;
+ } else if (ieee80211_is_disassoc(mgmt->frame_control) ||
+ ieee80211_is_deauth(mgmt->frame_control)) {
+ memcpy(scb_val.ea.octet, mgmt->da, ETH_ALEN);
+ scb_val.val = mgmt->u.disassoc.reason_code;
+ wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
+ sizeof(scb_val_t), true);
+ WL_DBG(("Disconnect STA : %s scb_val.val %d\n",
+ bcm_ether_ntoa((const struct ether_addr *)mgmt->da, eabuf),
+ scb_val.val));
+ /* Wait for the deauth event to come, supplicant will do the delete iface immediately
+ * and we will have problem in sending deauth frame if we delete the bss in firmware
+ */
+ wl_delay(400);
+ cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, true, GFP_KERNEL);
+ goto exit;
+
+ } else if (ieee80211_is_action(mgmt->frame_control)) {
+ /* Abort the dwell time of any previous off-channel
+ * action frame that may be still in effect. Sending
+ * off-channel action frames relies on the driver's
+ * scan engine. If a previous off-channel action frame
+ * tx is still in progress (including the dwell time),
+ * then this new action frame will not be sent out.
+ */
+ wl_notify_escan_complete(wl, dev, true, true);
+
}
- cfg80211_mgmt_tx_status(dev, *cookie, buf, len, true, GFP_KERNEL);
- goto exit;
+
} else {
- /* Abort the dwell time of any previous off-channel action frame that may
- * be still in effect. Sending off-channel action frames relies on the
- * driver's scan engine. If a previous off-channel action frame tx is
- * still in progress (including the dwell time), then this new action
- * frame will not be sent out.
- */
- wl_cfg80211_scan_abort(wl, dev);
+ WL_ERR(("Driver only allows MGMT packet type\n"));
+ goto exit;
}
+
af_params = (wl_af_params_t *) kzalloc(WL_WIFI_AF_PARAMS_SIZE, GFP_KERNEL);
if (af_params == NULL)
@@ -3307,7 +3478,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
action_frame = &af_params->action_frame;
/* Add the packet Id */
- action_frame->packetId = (u32) action_frame;
+ action_frame->packetId = *cookie;
WL_DBG(("action frame %d\n", action_frame->packetId));
/* Add BSSID */
memcpy(&action_frame->da, &mgmt->da[0], ETHER_ADDR_LEN);
@@ -3321,6 +3492,15 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
af_params->channel =
ieee80211_frequency_to_channel(channel->center_freq);
+ if (channel->band == IEEE80211_BAND_5GHZ) {
+ WL_DBG(("5GHz channel %d", af_params->channel));
+ err = wldev_ioctl(dev, WLC_SET_CHANNEL,
+ &af_params->channel, sizeof(af_params->channel), true);
+ if (err < 0) {
+ WL_ERR(("WLC_SET_CHANNEL error %d\n", err));
+ }
+ }
+
/* Add the dwell time
* Dwell time to stay off-channel to wait for a response action frame
* after transmitting an GO Negotiation action frame
@@ -3328,28 +3508,74 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
af_params->dwell_time = WL_DWELL_TIME;
memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], action_frame->len);
+ if (wl_cfgp2p_is_pub_action(action_frame->data, action_frame->len)) {
+ act_frm = (wifi_p2p_pub_act_frame_t *) (action_frame->data);
+ WL_DBG(("P2P PUB action_frame->len: %d chan %d category %d subtype %d\n",
+ action_frame->len, af_params->channel,
+ act_frm->category, act_frm->subtype));
+ } else if (wl_cfgp2p_is_p2p_action(action_frame->data, action_frame->len)) {
+ p2p_act_frm = (wifi_p2p_action_frame_t *) (action_frame->data);
+ WL_DBG(("P2P action_frame->len: %d chan %d category %d subtype %d\n",
+ action_frame->len, af_params->channel,
+ p2p_act_frm->category, p2p_act_frm->subtype));
+ } else if (wl_cfgp2p_is_gas_action(action_frame->data, action_frame->len)) {
+ sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *) (action_frame->data);
+ WL_DBG(("Service Discovery action_frame->len: %d chan %d category %d action %d\n",
+ action_frame->len, af_params->channel,
+ sd_act_frm->category, sd_act_frm->action));
+
+ }
+ wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len);
+ /*
+ * To make sure to send successfully action frame, we have to turn off mpc
+ */
- act_frm = (wifi_p2p_pub_act_frame_t *) (action_frame->data);
- WL_DBG(("action_frame->len: %d chan %d category %d subtype %d\n",
- action_frame->len, af_params->channel,
- act_frm->category, act_frm->subtype));
- if (wl->p2p->vif_created) {
- /*
- * To make sure to send successfully action frame, we have to turn off mpc
+ if (act_frm && ((act_frm->subtype == P2P_PAF_GON_REQ) ||
+ (act_frm->subtype == P2P_PAF_GON_RSP) ||
+ (act_frm->subtype == P2P_PAF_GON_CONF) ||
+ (act_frm->subtype == P2P_PAF_PROVDIS_REQ))) {
+ wldev_iovar_setint(dev, "mpc", 0);
+ }
+ if (act_frm->subtype == P2P_PAF_GON_RSP)
+ retry_cnt = 1;
+ else retry_cnt = WL_ACT_FRAME_RETRY;
+
+ if (act_frm && act_frm->subtype == P2P_PAF_DEVDIS_REQ) {
+ af_params->dwell_time = WL_LONG_DWELL_TIME;
+ } else if (act_frm &&
+ (act_frm->subtype == P2P_PAF_PROVDIS_REQ ||
+ act_frm->subtype == P2P_PAF_PROVDIS_RSP ||
+ act_frm->subtype == P2P_PAF_GON_RSP)) {
+ af_params->dwell_time = WL_MED_DWELL_TIME;
+ }
+
+ if (IS_P2P_SOCIAL(af_params->channel) &&
+ (IS_P2P_PUB_ACT_REQ(act_frm, &act_frm->elts[0], action_frame->len) ||
+ IS_GAS_REQ(sd_act_frm, action_frame->len)) &&
+ wl_to_p2p_bss_saved_ie(wl, P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie_len) {
+ /* channel offload require P2P IE for Probe request
+ * otherwise, we will use wl_cfgp2p_tx_action_frame directly.
+ * channel offload for action request frame
*/
- if ((act_frm->subtype == P2P_PAF_GON_REQ)||
- (act_frm->subtype == P2P_PAF_GON_RSP)) {
- wldev_iovar_setint(dev, "mpc", 0);
- } else if (act_frm->subtype == P2P_PAF_GON_CONF) {
- wldev_iovar_setint(dev, "mpc", 1);
- } else if (act_frm->subtype == P2P_PAF_DEVDIS_REQ) {
- af_params->dwell_time = WL_LONG_DWELL_TIME;
- }
- }
- ack = (wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx)) ? false : true;
- cfg80211_mgmt_tx_status(dev, *cookie, buf, len, ack, GFP_KERNEL);
+ /* channel offload for action request frame */
+ ack = wl_cfg80211_send_at_common_channel(wl, dev, af_params);
+ } else {
+ ack = (wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx)) ? false : true;
+ if (!ack) {
+ for (retry = 1; retry < retry_cnt; retry++) {
+ ack = (wl_cfgp2p_tx_action_frame(wl, dev,
+ af_params, bssidx)) ? false : true;
+ if (ack)
+ break;
+ }
+ }
+ }
+ cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, ack, GFP_KERNEL);
+ if (act_frm && act_frm->subtype == P2P_PAF_GON_CONF) {
+ wldev_iovar_setint(dev, "mpc", 1);
+ }
kfree(af_params);
exit:
return err;
@@ -3403,8 +3629,21 @@ wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
{
s32 channel;
s32 err = BCME_OK;
+ struct wl_priv *wl = wiphy_priv(wiphy);
+ if (wl->p2p_net == dev) {
+ dev = wl_to_prmry_ndev(wl);
+ }
channel = ieee80211_frequency_to_channel(chan->center_freq);
+
+ if (wl_get_drv_status(wl, AP_CREATING, dev)) {
+ WL_TRACE(("<0> %s: as!!! in AP creating mode, save chan num:%d\n",
+ __FUNCTION__, channel));
+ wl->hostapd_chan = channel;
+ if (channel == 14)
+ return err; /* hostapd requested ch auto-select, will be done later */
+ }
+
WL_DBG(("netdev_ifidx(%d), chan_type(%d) target channel(%d) \n",
dev->ifindex, channel_type, channel));
err = wldev_ioctl(dev, WLC_SET_CHANNEL, &channel, sizeof(channel), true);
@@ -3419,8 +3658,7 @@ wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx)
{
s32 len = 0;
s32 err = BCME_OK;
- u16 auth = 0; /* d11 open authentication */
- u16 count;
+ u16 auth = WL_AUTH_OPEN_SYSTEM; /* d11 open authentication */
u32 wsec;
u32 pval = 0;
u32 gval = 0;
@@ -3458,7 +3696,7 @@ wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx)
len -= WPA_SUITE_LEN;
/* check the unicast cipher */
ucast = (wpa_suite_ucast_t *)&mcast[1];
- count = ltoh16_ua(&ucast->count);
+ ltoh16_ua(&ucast->count);
tmp = ucast->list[0].oui;
switch (tmp[DOT11_OUI_LEN]) {
case WPA_CIPHER_NONE:
@@ -3481,7 +3719,7 @@ wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx)
wsec = (pval | gval | SES_OW_ENABLED);
/* check the AKM */
mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[1];
- count = ltoh16_ua(&mgmt->count);
+ ltoh16_ua(&mgmt->count);
tmp = (u8 *)&mgmt->list[0];
switch (tmp[DOT11_OUI_LEN]) {
case RSN_AKM_NONE:
@@ -3524,7 +3762,7 @@ wl_validate_wpaie(struct net_device *dev, wpa_ie_fixed_t *wpaie, s32 bssidx)
wpa_suite_mcast_t *mcast;
wpa_suite_ucast_t *ucast;
wpa_suite_auth_key_mgmt_t *mgmt;
- u16 auth = 0; /* d11 open authentication */
+ u16 auth = WL_AUTH_OPEN_SYSTEM; /* d11 open authentication */
u16 count;
s32 err = BCME_OK;
s32 len = 0;
@@ -3677,20 +3915,28 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
wpa_ie_fixed_t *wpa_ie;
bcm_tlv_t *wpa2_ie;
wifi_p2p_ie_t *p2p_ie;
+ wifi_wfd_ie_t *wfd_ie;
bool is_bssup = false;
bool update_bss = false;
bool pbc = false;
u16 wpsie_len = 0;
u16 p2pie_len = 0;
+ u32 wfdie_len = 0;
u8 beacon_ie[IE_MAX_LEN];
s32 ie_offset = 0;
- s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
+ s32 bssidx = 0;
s32 infra = 1;
s32 join_params_size = 0;
s32 ap = 0;
WL_DBG(("interval (%d) dtim_period (%d) head_len (%d) tail_len (%d)\n",
info->interval, info->dtim_period, info->head_len, info->tail_len));
- if (wl->p2p_supported && p2p_on(wl) &&
+
+ if (wl->p2p_net == dev) {
+ dev = wl_to_prmry_ndev(wl);
+ }
+
+ bssidx = wl_cfgp2p_find_idx(wl, dev);
+ if (p2p_is_on(wl) &&
(bssidx == wl_to_p2p_bss_bssidx(wl,
P2PAPI_BSSCFG_CONNECTION))) {
memset(beacon_ie, 0, sizeof(beacon_ie));
@@ -3728,21 +3974,29 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
if ((p2p_ie = wl_cfgp2p_find_p2pie((u8 *)info->tail, info->tail_len)) != NULL) {
/* Total length of P2P Information Element */
p2pie_len = p2p_ie->len + sizeof(p2p_ie->len) + sizeof(p2p_ie->id);
- #ifdef ENABLE_DRIVER_CHANGE_IFADDR /* We are now doing this in supplicant */
- /* Have to change device address in dev_id attribute because Supplicant
- * use primary eth0 address
- */
- wl_cfg80211_change_ifaddr((u8 *)p2p_ie, &wl->p2p_dev_addr, P2P_SEID_DEV_ID);
- #endif
memcpy(&beacon_ie[wpsie_len], p2p_ie, p2pie_len);
} else {
WL_ERR(("No P2PIE in beacon \n"));
}
+ /* find the WFD IEs */
+ if ((wfd_ie = wl_cfgp2p_find_wfdie((u8 *)info->tail, info->tail_len)) != NULL) {
+ /* Total length of P2P Information Element */
+ wfdie_len = wfd_ie->len + sizeof(wfd_ie->len) + sizeof(wfd_ie->id);
+ if ((wpsie_len + p2pie_len + wfdie_len) < IE_MAX_LEN) {
+ memcpy(&beacon_ie[wpsie_len + p2pie_len], wfd_ie, wfdie_len);
+ } else {
+ WL_ERR(("Found WFD IE but there is no space, (%d)(%d)(%d)\n",
+ wpsie_len, p2pie_len, wfdie_len));
+ wfdie_len = 0;
+ }
+ } else {
+ WL_ERR(("No WFDIE in beacon \n"));
+ }
/* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */
- wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
+ wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
wl_cfgp2p_set_management_ie(wl, dev, bssidx, VNDR_IE_BEACON_FLAG,
- beacon_ie, wpsie_len + p2pie_len);
+ beacon_ie, wpsie_len + p2pie_len + wfdie_len);
/* find the RSN_IE */
if ((wpa2_ie = bcm_parse_tlvs((u8 *)info->tail, info->tail_len,
@@ -3763,17 +4017,18 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
goto exit;
}
err = wldev_iovar_setbuf_bsscfg(dev, "ssid", &wl->p2p->ssid,
- sizeof(wl->p2p->ssid), ioctlbuf, sizeof(ioctlbuf), bssidx);
+ sizeof(wl->p2p->ssid), wl->ioctl_buf, WLC_IOCTL_MAXLEN,
+ bssidx, &wl->ioctl_buf_sync);
if (err < 0) {
WL_ERR(("GO SSID setting error %d\n", err));
goto exit;
}
- if ((err = wl_cfgp2p_bss(dev, bssidx, 1)) < 0) {
+ if ((err = wl_cfgp2p_bss(wl, dev, bssidx, 1)) < 0) {
WL_ERR(("GO Bring up error %d\n", err));
goto exit;
}
}
- } else if (wl_get_drv_status(wl, AP_CREATING)) {
+ } else if (wl_get_drv_status(wl, AP_CREATING, dev)) {
ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
ap = 1;
/* find the SSID */
@@ -3791,6 +4046,26 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
WL_ERR(("setting AP mode failed %d \n", err));
return err;
}
+
+ /* if requested, do softap ch autoselect */
+ if (wl->hostapd_chan == 14) {
+ int auto_chan;
+ if ((err = wldev_get_auto_channel(dev, &auto_chan)) != 0) {
+ WL_ERR(("softap: auto chan select failed,"
+ " will use ch 6\n"));
+ auto_chan = 6;
+ } else {
+ printf("<0>softap: got auto ch:%d\n", auto_chan);
+ }
+ err = wldev_ioctl(dev, WLC_SET_CHANNEL,
+ &auto_chan, sizeof(auto_chan), true);
+ if (err < 0) {
+ WL_ERR(("softap: WLC_SET_CHANNEL error %d chip"
+ " may not be supporting this channel\n", err));
+ return err;
+ }
+ }
+
/* find the RSN_IE */
if ((wpa2_ie = bcm_parse_tlvs((u8 *)info->tail, info->tail_len,
DOT11_MNG_RSN_ID)) != NULL) {
@@ -3846,9 +4121,9 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
memcpy(beacon_ie, wps_ie, wpsie_len);
wl_cfgp2p_set_management_ie(wl, dev, bssidx, VNDR_IE_BEACON_FLAG,
beacon_ie, wpsie_len);
- wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL);
+ wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL);
/* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */
- wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
+ wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
} else {
WL_DBG(("No WPSIE in beacon \n"));
}
@@ -3879,11 +4154,11 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
/* create softap */
if ((err = wldev_ioctl(dev, WLC_SET_SSID, &join_params,
join_params_size, true)) == 0) {
- wl_clr_drv_status(wl, AP_CREATING);
- wl_set_drv_status(wl, AP_CREATED);
+ wl_clr_drv_status(wl, AP_CREATING, dev);
+ wl_set_drv_status(wl, AP_CREATED, dev);
}
}
- } else if (wl_get_drv_status(wl, AP_CREATED)) {
+ } else if (wl_get_drv_status(wl, AP_CREATED, dev)) {
ap = 1;
/* find the WPSIE */
if ((wps_ie = wl_cfgp2p_find_wpsie((u8 *)info->tail, info->tail_len)) != NULL) {
@@ -3899,14 +4174,14 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
memcmp(wl->ap_info->wps_ie, wps_ie, wpsie_len)) {
WL_DBG((" WPS IE is changed\n"));
kfree(wl->ap_info->wps_ie);
- wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL);
+ wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL);
/* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */
- wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
+ wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
} else if (wl->ap_info->wps_ie == NULL) {
WL_DBG((" WPS IE is added\n"));
- wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL);
+ wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL);
/* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */
- wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
+ wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
}
/* find the RSN_IE */
if ((wpa2_ie = bcm_parse_tlvs((u8 *)info->tail, info->tail_len,
@@ -3972,12 +4247,12 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
}
if (update_bss) {
wl->ap_info->security_mode = true;
- wl_cfgp2p_bss(dev, bssidx, 0);
+ wl_cfgp2p_bss(wl, dev, bssidx, 0);
if (wl_validate_wpa2ie(dev, wpa2_ie, bssidx) < 0 ||
wl_validate_wpaie(dev, wpa_ie, bssidx) < 0) {
return BCME_ERROR;
}
- wl_cfgp2p_bss(dev, bssidx, 1);
+ wl_cfgp2p_bss(wl, dev, bssidx, 1);
}
}
} else {
@@ -3990,6 +4265,108 @@ exit:
return err;
}
+#ifdef WL_SCHED_SCAN
+#define PNO_TIME 30
+#define PNO_REPEAT 4
+#define PNO_FREQ_EXPO_MAX 3
+int wl_cfg80211_sched_scan_start(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct cfg80211_sched_scan_request *request)
+{
+ ushort pno_time = PNO_TIME;
+ int pno_repeat = PNO_REPEAT;
+ int pno_freq_expo_max = PNO_FREQ_EXPO_MAX;
+ wlc_ssid_t ssids_local[MAX_PFN_LIST_COUNT];
+ struct wl_priv *wl = wiphy_priv(wiphy);
+ struct cfg80211_ssid *ssid = NULL;
+ int ssid_count = 0;
+ int i;
+ int ret = 0;
+
+ WL_DBG(("Enter n_match_sets:%d n_ssids:%d \n",
+ request->n_match_sets, request->n_ssids));
+ WL_DBG(("ssids:%d pno_time:%d pno_repeat:%d pno_freq:%d \n",
+ request->n_ssids, pno_time, pno_repeat, pno_freq_expo_max));
+
+#if defined(WL_ENABLE_P2P_IF)
+ /* While GO is operational, PNO is not supported */
+ if (dhd_cfg80211_get_opmode(wl) & P2P_GO_ENABLED) {
+ WL_DBG(("PNO not enabled! op_mode: P2P GO"));
+ return -1;
+ }
+#endif
+
+ if (!request || !request->n_ssids || !request->n_match_sets) {
+ WL_ERR(("Invalid sched scan req!! n_ssids:%d \n", request->n_ssids));
+ return -EINVAL;
+ }
+
+ memset(&ssids_local, 0, sizeof(ssids_local));
+
+ if (request->n_match_sets > 0) {
+ for (i = 0; i < request->n_match_sets; i++) {
+ ssid = &request->match_sets[i].ssid;
+ memcpy(ssids_local[i].SSID, ssid->ssid, ssid->ssid_len);
+ ssids_local[i].SSID_len = ssid->ssid_len;
+ WL_DBG((">>> PNO filter set for ssid (%s) \n", ssid->ssid));
+ ssid_count++;
+ }
+ }
+
+ if (request->n_ssids > 0) {
+ for (i = 0; i < request->n_ssids; i++) {
+ /* Active scan req for ssids */
+ WL_DBG((">>> Active scan req for ssid (%s) \n", request->ssids[i].ssid));
+
+ /* match_set ssids is a supert set of n_ssid list, so we need
+ * not add these set seperately
+ */
+ }
+ }
+
+ if (ssid_count) {
+ if ((ret = dhd_dev_pno_set(dev, ssids_local, request->n_match_sets,
+ pno_time, pno_repeat, pno_freq_expo_max)) < 0) {
+ WL_ERR(("PNO setup failed!! ret=%d \n", ret));
+ return -EINVAL;
+ }
+
+ /* Enable the PNO */
+ if (dhd_dev_pno_enable(dev, 1) < 0) {
+ WL_ERR(("PNO enable failed!! ret=%d \n", ret));
+ return -EINVAL;
+ }
+ wl->sched_scan_req = request;
+ } else {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev)
+{
+ struct wl_priv *wl = wiphy_priv(wiphy);
+
+ WL_DBG(("Enter \n"));
+
+ if (dhd_dev_pno_enable(dev, 0) < 0)
+ WL_ERR(("PNO disable failed"));
+
+ if (dhd_dev_pno_reset(dev) < 0)
+ WL_ERR(("PNO reset failed"));
+
+ if (wl->scan_request && wl->sched_scan_running) {
+ wl_notify_escan_complete(wl, dev, true, true);
+ }
+
+ wl->sched_scan_req = NULL;
+ wl->sched_scan_running = FALSE;
+
+ return 0;
+}
+#endif /* WL_SCHED_SCAN */
+
static struct cfg80211_ops wl_cfg80211_ops = {
.add_virtual_intf = wl_cfg80211_add_virtual_iface,
.del_virtual_intf = wl_cfg80211_del_virtual_iface,
@@ -4022,9 +4399,13 @@ static struct cfg80211_ops wl_cfg80211_ops = {
.set_channel = wl_cfg80211_set_channel,
.set_beacon = wl_cfg80211_add_set_beacon,
.add_beacon = wl_cfg80211_add_set_beacon,
+#ifdef WL_SCHED_SCAN
+ .sched_scan_start = wl_cfg80211_sched_scan_start,
+ .sched_scan_stop = wl_cfg80211_sched_scan_stop,
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) */
};
-static s32 wl_mode_to_nl80211_iftype(s32 mode)
+s32 wl_mode_to_nl80211_iftype(s32 mode)
{
s32 err = 0;
@@ -4042,30 +4423,30 @@ static s32 wl_mode_to_nl80211_iftype(s32 mode)
return err;
}
-static struct wireless_dev *wl_alloc_wdev(struct device *sdiofunc_dev)
+static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev)
{
- struct wireless_dev *wdev;
s32 err = 0;
- wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
- if (unlikely(!wdev)) {
- WL_ERR(("Could not allocate wireless device\n"));
- return ERR_PTR(-ENOMEM);
- }
wdev->wiphy =
wiphy_new(&wl_cfg80211_ops, sizeof(struct wl_priv));
if (unlikely(!wdev->wiphy)) {
WL_ERR(("Couldn not allocate wiphy device\n"));
err = -ENOMEM;
- goto wiphy_new_out;
+ return err;
}
set_wiphy_dev(wdev->wiphy, sdiofunc_dev);
wdev->wiphy->max_scan_ie_len = WL_SCAN_IE_LEN_MAX;
/* Report how many SSIDs Driver can support per Scan request */
wdev->wiphy->max_scan_ssids = WL_SCAN_PARAMS_SSID_MAX;
wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
+#ifdef WL_SCHED_SCAN
+ wdev->wiphy->max_sched_scan_ssids = MAX_PFN_LIST_COUNT;
+ wdev->wiphy->max_match_sets = MAX_PFN_LIST_COUNT;
+ wdev->wiphy->max_sched_scan_ie_len = WL_SCAN_IE_LEN_MAX;
+ wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
+#endif /* WL_SCHED_SCAN */
wdev->wiphy->interface_modes =
- BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC)
- | BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_MONITOR);
+ BIT(NL80211_IFTYPE_STATION)
+ | BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_MONITOR);
wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a;
@@ -4085,6 +4466,9 @@ static struct wireless_dev *wl_alloc_wdev(struct device *sdiofunc_dev)
WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS |
#endif
WIPHY_FLAG_4ADDR_STATION;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+ wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
+#endif
#ifdef ENABLE_CUSTOM_REGULATORY_DOMAIN
WL_DBG(("Registering custom regulatory)\n"));
@@ -4095,39 +4479,28 @@ static struct wireless_dev *wl_alloc_wdev(struct device *sdiofunc_dev)
err = wiphy_register(wdev->wiphy);
if (unlikely(err < 0)) {
WL_ERR(("Couldn not register wiphy device (%d)\n", err));
- goto wiphy_register_out;
+ wiphy_free(wdev->wiphy);
}
- return wdev;
-
-wiphy_register_out:
- wiphy_free(wdev->wiphy);
-
-wiphy_new_out:
- kfree(wdev);
-
- return ERR_PTR(err);
+ return err;
}
static void wl_free_wdev(struct wl_priv *wl)
{
- int i;
struct wireless_dev *wdev = wl->wdev;
-
- if (unlikely(!wdev)) {
+ struct wiphy *wiphy;
+ if (!wdev) {
WL_ERR(("wdev is invalid\n"));
return;
}
-
- for (i = 0; i < VWDEV_CNT; i++) {
- if ((wl->vwdev[i] != NULL)) {
- kfree(wl->vwdev[i]);
- wl->vwdev[i] = NULL;
- }
- }
+ wiphy = wdev->wiphy;
wiphy_unregister(wdev->wiphy);
wdev->wiphy->dev.parent = NULL;
- wiphy_free(wdev->wiphy);
- kfree(wdev);
+
+ wl_delete_all_netinfo(wl);
+ wiphy_free(wiphy);
+ /* PLEASE do NOT call any function after wiphy_free, the driver's private structure "wl",
+ * which is the private part of wiphy, has been freed in wiphy_free !!!!!!!!!!!
+ */
}
static s32 wl_inform_bss(struct wl_priv *wl)
@@ -4157,6 +4530,7 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi)
struct wl_cfg80211_bss_info *notif_bss_info;
struct wl_scan_req *sr = wl_to_sr(wl);
struct beacon_proberesp *beacon_proberesp;
+ struct cfg80211_bss *cbss = NULL;
s32 mgmt_type;
s32 signal;
u32 freq;
@@ -4180,6 +4554,11 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi)
band = wiphy->bands[IEEE80211_BAND_2GHZ];
else
band = wiphy->bands[IEEE80211_BAND_5GHZ];
+ if (!band) {
+ WL_ERR(("No valid band"));
+ kfree(notif_bss_info);
+ return -EINVAL;
+ }
notif_bss_info->rssi = dtoh16(bi->RSSI);
memcpy(mgmt->bssid, &bi->BSSID, ETHER_ADDR_LEN);
mgmt_type = wl->active_scan ?
@@ -4206,8 +4585,13 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi)
freq = ieee80211_channel_to_frequency(notif_bss_info->channel, band->band);
#endif
channel = ieee80211_get_channel(wiphy, freq);
+ if (!channel) {
+ WL_ERR(("No valid channel"));
+ kfree(notif_bss_info);
+ return -EINVAL;
+ }
- WL_DBG(("SSID : \"%s\", rssi %d, channel %d, capability : 0x04%x, bssid %pM"
+ WL_DBG(("SSID : \"%s\", rssi %d, channel %d, capability : 0x04%x, bssid %pM "
"mgmt_type %d frame_len %d\n", bi->SSID,
notif_bss_info->rssi, notif_bss_info->channel,
mgmt->u.beacon.capab_info, &bi->BSSID, mgmt_type,
@@ -4215,13 +4599,41 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi)
signal = notif_bss_info->rssi * 100;
- if (unlikely(!cfg80211_inform_bss_frame(wiphy, channel, mgmt,
- le16_to_cpu(notif_bss_info->frame_len),
- signal, GFP_KERNEL))) {
+#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF)
+ if (wl->p2p && wl->p2p_net && wl->scan_request &&
+ ((wl->scan_request->dev == wl->p2p_net) ||
+ (wl->scan_request->dev == wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION)))){
+#else
+ if (p2p_is_on(wl) && ( p2p_scan(wl) ||
+ (wl->scan_request->dev == wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION)))) {
+#endif
+ /* find the P2PIE, if we do not find it, we will discard this frame */
+ wifi_p2p_ie_t * p2p_ie;
+ if ((p2p_ie = wl_cfgp2p_find_p2pie((u8 *)beacon_proberesp->variable,
+ wl_get_ielen(wl))) == NULL) {
+ WL_ERR(("Couldn't find P2PIE in probe response/beacon\n"));
+ kfree(notif_bss_info);
+ return err;
+ }
+ }
+
+ if (!mgmt->u.probe_resp.timestamp) {
+ struct timeval tv;
+
+ do_gettimeofday(&tv);
+ mgmt->u.probe_resp.timestamp = ((u64)tv.tv_sec * 1000000)
+ + tv.tv_usec;
+ }
+
+ cbss = cfg80211_inform_bss_frame(wiphy, channel, mgmt,
+ le16_to_cpu(notif_bss_info->frame_len), signal, GFP_KERNEL);
+ if (unlikely(!cbss)) {
WL_ERR(("cfg80211_inform_bss_frame error\n"));
kfree(notif_bss_info);
return -EINVAL;
}
+
+ cfg80211_put_bss(cbss);
kfree(notif_bss_info);
return err;
@@ -4233,7 +4645,7 @@ static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e, struct net
u32 status = ntoh32(e->status);
u16 flags = ntoh16(e->flags);
- WL_DBG(("event %d, status %d\n", event, status));
+ WL_DBG(("event %d, status %d flags %x\n", event, status, flags));
if (event == WLC_E_SET_SSID) {
if (status == WLC_E_STATUS_SUCCESS) {
if (!wl_is_ibssmode(wl, ndev))
@@ -4279,162 +4691,225 @@ static bool wl_is_nonetwork(struct wl_priv *wl, const wl_event_msg_t *e)
return false;
}
+/* The mainline kernel >= 3.2.0 has support for indicating new/del station
+ * to AP/P2P GO via events. If this change is backported to kernel for which
+ * this driver is being built, then define WL_CFG80211_STA_EVENT. You
+ * should use this new/del sta event mechanism for BRCM supplicant >= 22.
+ */
static s32
-wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
+wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev,
const wl_event_msg_t *e, void *data)
{
- bool act;
- bool isfree = false;
s32 err = 0;
- s32 freq;
- s32 channel;
- u8 body[200];
u32 event = ntoh32(e->event_type);
u32 reason = ntoh32(e->reason);
u32 len = ntoh32(e->datalen);
- u16 fc = 0;
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !defined(WL_CFG80211_STA_EVENT)
+ bool isfree = false;
u8 *mgmt_frame;
u8 bsscfgidx = e->bsscfgidx;
+ s32 freq;
+ s32 channel;
+ u8 body[WL_FRAME_LEN];
+ u16 fc = 0;
struct ieee80211_supported_band *band;
struct ether_addr da;
struct ether_addr bssid;
struct wiphy *wiphy = wl_to_wiphy(wl);
channel_info_t ci;
+#else
+ struct station_info sinfo;
+#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !WL_CFG80211_STA_EVENT */
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !defined(WL_CFG80211_STA_EVENT)
memset(body, 0, sizeof(body));
memset(&bssid, 0, ETHER_ADDR_LEN);
- WL_DBG(("Enter \n"));
+ WL_DBG(("Enter event %d ndev %p\n", event, ndev));
+ if (wl_get_mode_by_netdev(wl, ndev) == WL_INVALID)
+ return WL_INVALID;
- if (get_mode_by_netdev(wl, ndev) == WL_MODE_AP) {
- memcpy(body, data, len);
- wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
- NULL, 0, ioctlbuf, sizeof(ioctlbuf), bsscfgidx);
- memcpy(da.octet, ioctlbuf, ETHER_ADDR_LEN);
- err = wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false);
- switch (event) {
- case WLC_E_ASSOC_IND:
- fc = FC_ASSOC_REQ;
- break;
- case WLC_E_REASSOC_IND:
- fc = FC_REASSOC_REQ;
- break;
- case WLC_E_DISASSOC_IND:
- fc = FC_DISASSOC;
- break;
- case WLC_E_DEAUTH_IND:
- fc = FC_DISASSOC;
- break;
- case WLC_E_DEAUTH:
- fc = FC_DISASSOC;
- break;
- default:
- fc = 0;
- goto exit;
- }
- if ((err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci), false)))
- return err;
-
- channel = dtoh32(ci.hw_channel);
- if (channel <= CH_MAX_2G_CHANNEL)
- band = wiphy->bands[IEEE80211_BAND_2GHZ];
- else
- band = wiphy->bands[IEEE80211_BAND_5GHZ];
+ if (len > WL_FRAME_LEN) {
+ WL_ERR(("Received frame length %d from dongle is greater than"
+ " allocated body buffer len %d", len, WL_FRAME_LEN));
+ goto exit;
+ }
+ memcpy(body, data, len);
+ wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
+ NULL, 0, wl->ioctl_buf, WLC_IOCTL_MAXLEN, bsscfgidx, &wl->ioctl_buf_sync);
+ memcpy(da.octet, wl->ioctl_buf, ETHER_ADDR_LEN);
+ err = wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false);
+ switch (event) {
+ case WLC_E_ASSOC_IND:
+ fc = FC_ASSOC_REQ;
+ break;
+ case WLC_E_REASSOC_IND:
+ fc = FC_REASSOC_REQ;
+ break;
+ case WLC_E_DISASSOC_IND:
+ fc = FC_DISASSOC;
+ break;
+ case WLC_E_DEAUTH_IND:
+ fc = FC_DISASSOC;
+ break;
+ case WLC_E_DEAUTH:
+ fc = FC_DISASSOC;
+ break;
+ default:
+ fc = 0;
+ goto exit;
+ }
+ if ((err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci), false)))
+ return err;
+ channel = dtoh32(ci.hw_channel);
+ if (channel <= CH_MAX_2G_CHANNEL)
+ band = wiphy->bands[IEEE80211_BAND_2GHZ];
+ else
+ band = wiphy->bands[IEEE80211_BAND_5GHZ];
+ if (!band) {
+ WL_ERR(("No valid band"));
+ return -EINVAL;
+ }
#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
- freq = ieee80211_channel_to_frequency(channel);
+ freq = ieee80211_channel_to_frequency(channel);
#else
- freq = ieee80211_channel_to_frequency(channel, band->band);
+ freq = ieee80211_channel_to_frequency(channel, band->band);
#endif
- err = wl_frame_get_mgmt(fc, &da, &e->addr, &bssid,
+ err = wl_frame_get_mgmt(fc, &da, &e->addr, &bssid,
&mgmt_frame, &len, body);
- if (err < 0)
- goto exit;
- isfree = true;
+ if (err < 0)
+ goto exit;
+ isfree = true;
- if (event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) {
- cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
- } else if (event == WLC_E_DISASSOC_IND) {
- cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
- } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) {
- cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
+ if (event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) {
+ cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
+ } else if (event == WLC_E_DISASSOC_IND) {
+ cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
+ } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) {
+ cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
+ }
+
+exit:
+ if (isfree)
+ kfree(mgmt_frame);
+ return err;
+#else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0) && !WL_CFG80211_STA_EVENT */
+ sinfo.filled = 0;
+ if (((event == WLC_E_ASSOC_IND) || (event == WLC_E_REASSOC_IND)) &&
+ reason == DOT11_SC_SUCCESS) {
+ sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
+ if (!data) {
+ WL_ERR(("No IEs present in ASSOC/REASSOC_IND"));
+ return -EINVAL;
}
+ sinfo.assoc_req_ies = data;
+ sinfo.assoc_req_ies_len = len;
+ cfg80211_new_sta(ndev, e->addr.octet, &sinfo, GFP_ATOMIC);
+ } else if (event == WLC_E_DISASSOC_IND) {
+ cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC);
+ } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) {
+ cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC);
+ }
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0) && !WL_CFG80211_STA_EVENT */
+ return err;
+}
+static s32
+wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data)
+{
+ bool act;
+ s32 err = 0;
+ u32 event = ntoh32(e->event_type);
+ u32 reason;
+
+ if (wl_get_mode_by_netdev(wl, ndev) == WL_MODE_AP) {
+ wl_notify_connect_status_ap(wl, ndev, e, data);
} else {
- WL_DBG(("wl_notify_connect_status : event %d status : %d \n",
- ntoh32(e->event_type), ntoh32(e->status)));
+ WL_DBG(("wl_notify_connect_status : event %d status : %d ndev %p\n",
+ ntoh32(e->event_type), ntoh32(e->status), ndev));
+ if((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DISASSOC_IND)) {
+ reason = ntoh32(e->reason);
+ wl->deauth_reason = reason;
+ WL_ERR(("Received %s event with reason code: %d\n", (event == WLC_E_DEAUTH_IND)? "WLC_E_DEAUTH_IND":"WLC_E_DISASSOC_IND", reason));
+ }
if (wl_is_linkup(wl, e, ndev)) {
wl_link_up(wl);
act = true;
- wl_update_prof(wl, e, &act, WL_PROF_ACT);
- wl_update_prof(wl, NULL, (void *)(e->addr.octet), WL_PROF_BSSID);
+ wl_update_prof(wl, ndev, e, &act, WL_PROF_ACT);
+ wl_update_prof(wl, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID);
+ wl->deauth_reason = 0;
if (wl_is_ibssmode(wl, ndev)) {
printk("cfg80211_ibss_joined\n");
cfg80211_ibss_joined(ndev, (s8 *)&e->addr,
GFP_KERNEL);
WL_DBG(("joined in IBSS network\n"));
} else {
- if (!wl_get_drv_status(wl, DISCONNECTING)) {
- printk("wl_bss_connect_done succeeded status=(0x%x)\n",
- (int)wl->status);
+ if (!wl_get_drv_status(wl, DISCONNECTING, ndev)) {
+ printk("wl_bss_connect_done succeeded\n");
wl_bss_connect_done(wl, ndev, e, data, true);
WL_DBG(("joined in BSS network \"%s\"\n",
((struct wlc_ssid *)
- wl_read_prof(wl, WL_PROF_SSID))->SSID));
+ wl_read_prof(wl, ndev, WL_PROF_SSID))->SSID));
}
}
} else if (wl_is_linkdown(wl, e)) {
if (wl->scan_request) {
- del_timer_sync(&wl->scan_timeout);
if (wl->escan_on) {
- wl_notify_escan_complete(wl, true);
- } else
+ wl_notify_escan_complete(wl, ndev, true, true);
+ } else {
+ del_timer_sync(&wl->scan_timeout);
wl_iscan_aborted(wl);
+ }
}
- if (wl_get_drv_status(wl, CONNECTED)) {
+ if (wl_get_drv_status(wl, CONNECTED, ndev)) {
scb_val_t scbval;
- u8 *curbssid = wl_read_prof(wl, WL_PROF_BSSID);
- printk("link down, call cfg80211_disconnected\n");
- wl_clr_drv_status(wl, CONNECTED);
- /* To make sure disconnect, explictly send dissassoc
- * for BSSID 00:00:00:00:00:00 issue
- */
- scbval.val = WLAN_REASON_DEAUTH_LEAVING;
-
- memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
- scbval.val = htod32(scbval.val);
- wldev_ioctl(ndev, WLC_DISASSOC, &scbval,
- sizeof(scb_val_t), true);
- cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL);
- wl_link_down(wl);
- wl_init_prof(wl);
- } else if (wl_get_drv_status(wl, CONNECTING)) {
+ u8 *curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID);
+ wl_clr_drv_status(wl, CONNECTED, ndev);
+ if (! wl_get_drv_status(wl, DISCONNECTING, ndev)) {
+ /* To make sure disconnect, explictly send dissassoc
+ * for BSSID 00:00:00:00:00:00 issue
+ */
+ scbval.val = WLAN_REASON_DEAUTH_LEAVING;
+
+ memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
+ scbval.val = htod32(scbval.val);
+ wldev_ioctl(ndev, WLC_DISASSOC, &scbval,
+ sizeof(scb_val_t), true);
+ WL_ERR(("link down, calling cfg80211_disconnected with deauth_reason:%d\n", wl->deauth_reason));
+ cfg80211_disconnected(ndev, wl->deauth_reason , NULL, 0, GFP_KERNEL);
+ wl_link_down(wl);
+ wl_init_prof(wl, ndev);
+ }
+ }
+ else if (wl_get_drv_status(wl, CONNECTING, ndev)) {
printk("link down, during connecting\n");
wl_bss_connect_done(wl, ndev, e, data, false);
}
- wl_clr_drv_status(wl, DISCONNECTING);
+ wl_clr_drv_status(wl, DISCONNECTING, ndev);
} else if (wl_is_nonetwork(wl, e)) {
printk("connect failed event=%d e->status 0x%x\n",
event, (int)ntoh32(e->status));
/* Clean up any pending scan request */
if (wl->scan_request) {
- del_timer_sync(&wl->scan_timeout);
if (wl->escan_on) {
- wl_notify_escan_complete(wl, true);
- } else
+ wl_notify_escan_complete(wl, ndev, true, true);
+ } else {
+ del_timer_sync(&wl->scan_timeout);
wl_iscan_aborted(wl);
+ }
}
- if (wl_get_drv_status(wl, CONNECTING))
+ if (wl_get_drv_status(wl, CONNECTING, ndev))
wl_bss_connect_done(wl, ndev, e, data, false);
} else {
printk("%s nothing\n", __FUNCTION__);
}
}
-exit:
- if (isfree)
- kfree(mgmt_frame);
return err;
}
@@ -4448,50 +4923,17 @@ wl_notify_roaming_status(struct wl_priv *wl, struct net_device *ndev,
u32 status = be32_to_cpu(e->status);
WL_DBG(("Enter \n"));
if (event == WLC_E_ROAM && status == WLC_E_STATUS_SUCCESS) {
- if (wl_get_drv_status(wl, CONNECTED))
+ if (wl_get_drv_status(wl, CONNECTED, ndev))
wl_bss_roaming_done(wl, ndev, e, data);
else
wl_bss_connect_done(wl, ndev, e, data, true);
act = true;
- wl_update_prof(wl, e, &act, WL_PROF_ACT);
- wl_update_prof(wl, NULL, (void *)(e->addr.octet), WL_PROF_BSSID);
+ wl_update_prof(wl, ndev, e, &act, WL_PROF_ACT);
+ wl_update_prof(wl, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID);
}
return err;
}
-static __used s32
-wl_dev_bufvar_set(struct net_device *dev, s8 *name, s8 *buf, s32 len)
-{
- struct wl_priv *wl = wlcfg_drv_priv;
- u32 buflen;
-
- buflen = bcm_mkiovar(name, buf, len, wl->ioctl_buf, WL_IOCTL_LEN_MAX);
- BUG_ON(unlikely(!buflen));
-
- return wldev_ioctl(dev, WLC_SET_VAR, wl->ioctl_buf, buflen, true);
-}
-
-static s32
-wl_dev_bufvar_get(struct net_device *dev, s8 *name, s8 *buf,
- s32 buf_len)
-{
- struct wl_priv *wl = wlcfg_drv_priv;
- u32 len;
- s32 err = 0;
-
- len = bcm_mkiovar(name, NULL, 0, wl->ioctl_buf, WL_IOCTL_LEN_MAX);
- BUG_ON(unlikely(!len));
- err = wldev_ioctl(dev, WLC_GET_VAR, (void *)wl->ioctl_buf,
- WL_IOCTL_LEN_MAX, false);
- if (unlikely(err)) {
- WL_ERR(("error (%d)\n", err));
- return err;
- }
- memcpy(buf, wl->ioctl_buf, buf_len);
-
- return err;
-}
-
static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev)
{
wl_assoc_info_t assoc_info;
@@ -4499,8 +4941,8 @@ static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev)
s32 err = 0;
WL_DBG(("Enter \n"));
- err = wl_dev_bufvar_get(ndev, "assoc_info", wl->extra_buf,
- WL_ASSOC_INFO_MAX);
+ err = wldev_iovar_getbuf(ndev, "assoc_info", NULL, 0, wl->extra_buf,
+ WL_ASSOC_INFO_MAX, NULL);
if (unlikely(err)) {
WL_ERR(("could not get assoc info (%d)\n", err));
return err;
@@ -4518,8 +4960,8 @@ static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev)
bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie));
}
if (assoc_info.req_len) {
- err = wl_dev_bufvar_get(ndev, "assoc_req_ies", wl->extra_buf,
- WL_ASSOC_INFO_MAX);
+ err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, wl->extra_buf,
+ WL_ASSOC_INFO_MAX, NULL);
if (unlikely(err)) {
WL_ERR(("could not get assoc req (%d)\n", err));
return err;
@@ -4539,8 +4981,8 @@ static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev)
conn_info->req_ie_len = 0;
}
if (assoc_info.resp_len) {
- err = wl_dev_bufvar_get(ndev, "assoc_resp_ies", wl->extra_buf,
- WL_ASSOC_INFO_MAX);
+ err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0, wl->extra_buf,
+ WL_ASSOC_INFO_MAX, NULL);
if (unlikely(err)) {
WL_ERR(("could not get assoc resp (%d)\n", err));
return err;
@@ -4602,26 +5044,27 @@ static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev)
struct wl_bss_info *bi;
struct wlc_ssid *ssid;
struct bcm_tlv *tim;
- u16 beacon_interval;
- u8 dtim_period;
+ s32 beacon_interval;
+ s32 dtim_period;
size_t ie_len;
u8 *ie;
u8 *curbssid;
s32 err = 0;
struct wiphy *wiphy;
+
wiphy = wl_to_wiphy(wl);
if (wl_is_ibssmode(wl, ndev))
return err;
- ssid = (struct wlc_ssid *)wl_read_prof(wl, WL_PROF_SSID);
- curbssid = wl_read_prof(wl, WL_PROF_BSSID);
+ ssid = (struct wlc_ssid *)wl_read_prof(wl, ndev, WL_PROF_SSID);
+ curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID);
bss = cfg80211_get_bss(wiphy, NULL, curbssid,
ssid->SSID, ssid->SSID_len, WLAN_CAPABILITY_ESS,
WLAN_CAPABILITY_ESS);
mutex_lock(&wl->usr_sync);
- if (unlikely(!bss)) {
+ if (!bss) {
WL_DBG(("Could not find the AP\n"));
*(u32 *) wl->extra_buf = htod32(WL_EXTRA_BUF_MAX);
err = wldev_ioctl(ndev, WLC_GET_BSS_INFO,
@@ -4657,7 +5100,7 @@ static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev)
/*
* active scan was done so we could not get dtim
* information out of probe response.
- * so we speficially query dtim information to dongle.
+ * so we speficially query dtim information.
*/
err = wldev_ioctl(ndev, WLC_GET_DTIMPRD,
&dtim_period, sizeof(dtim_period), false);
@@ -4667,8 +5110,8 @@ static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev)
}
}
- wl_update_prof(wl, NULL, &beacon_interval, WL_PROF_BEACONINT);
- wl_update_prof(wl, NULL, &dtim_period, WL_PROF_DTIMPERIOD);
+ wl_update_prof(wl, ndev, NULL, &beacon_interval, WL_PROF_BEACONINT);
+ wl_update_prof(wl, ndev, NULL, &dtim_period, WL_PROF_DTIMPERIOD);
update_bss_info_out:
mutex_unlock(&wl->usr_sync);
@@ -4684,8 +5127,8 @@ wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev,
u8 *curbssid;
wl_get_assoc_ies(wl, ndev);
- wl_update_prof(wl, NULL, (void *)(e->addr.octet), WL_PROF_BSSID);
- curbssid = wl_read_prof(wl, WL_PROF_BSSID);
+ wl_update_prof(wl, ndev, NULL, (void *)(e->addr.octet), WL_PROF_BSSID);
+ curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID);
wl_update_bss_info(wl, ndev);
wl_update_pmklist(ndev, wl->pmk_list, err);
cfg80211_roamed(ndev,
@@ -4697,7 +5140,7 @@ wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev,
conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
WL_DBG(("Report roaming result\n"));
- wl_set_drv_status(wl, CONNECTED);
+ wl_set_drv_status(wl, CONNECTED, ndev);
return err;
}
@@ -4708,20 +5151,21 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev,
{
struct wl_connect_info *conn_info = wl_to_conn(wl);
s32 err = 0;
- u8 *curbssid = wl_read_prof(wl, WL_PROF_BSSID);
+ u8 *curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID);
+
WL_DBG((" enter\n"));
if (wl->scan_request) {
- wl_cfg80211_scan_abort(wl, ndev);
+ wl_notify_escan_complete(wl, ndev, true, true);
}
- if (wl_get_drv_status(wl, CONNECTING)) {
- wl_clr_drv_status(wl, CONNECTING);
+ if (wl_get_drv_status(wl, CONNECTING, ndev)) {
+ wl_clr_drv_status(wl, CONNECTING, ndev);
if (completed) {
wl_get_assoc_ies(wl, ndev);
- wl_update_prof(wl, NULL, (void *)(e->addr.octet), WL_PROF_BSSID);
- curbssid = wl_read_prof(wl, WL_PROF_BSSID);
+ wl_update_prof(wl, ndev, NULL, (void *)(e->addr.octet), WL_PROF_BSSID);
+ curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID);
wl_update_bss_info(wl, ndev);
wl_update_pmklist(ndev, wl->pmk_list, err);
- wl_set_drv_status(wl, CONNECTED);
+ wl_set_drv_status(wl, CONNECTED, ndev);
}
cfg80211_connect_result(ndev,
curbssid,
@@ -4759,6 +5203,28 @@ wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev,
return 0;
}
+#ifdef PNO_SUPPORT
+static s32
+wl_notify_pfn_status(struct wl_priv *wl, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data)
+{
+ WL_ERR((" PNO Event\n"));
+
+ mutex_lock(&wl->usr_sync);
+#ifndef WL_SCHED_SCAN
+ /* TODO: Use cfg80211_sched_scan_results(wiphy); */
+ cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL);
+#else
+ /* If cfg80211 scheduled scan is supported, report the pno results via sched
+ * scan results
+ */
+ wl_notify_sched_scan_results(wl, ndev, e, data);
+#endif /* WL_SCHED_SCAN */
+ mutex_unlock(&wl->usr_sync);
+ return 0;
+}
+#endif /* PNO_SUPPORT */
+
static s32
wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev,
const wl_event_msg_t *e, void *data)
@@ -4770,11 +5236,15 @@ wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev,
unsigned long flags;
WL_DBG(("Enter \n"));
+ if (!wl_get_drv_status(wl, SCANNING, ndev)) {
+ WL_ERR(("scan is not ready \n"));
+ return err;
+ }
if (wl->iscan_on && wl->iscan_kickstart)
return wl_wakeup_iscan(wl_to_iscan(wl));
mutex_lock(&wl->usr_sync);
- wl_clr_drv_status(wl, SCANNING);
+ wl_clr_drv_status(wl, SCANNING, ndev);
err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &channel_inform,
sizeof(channel_inform), false);
if (unlikely(err)) {
@@ -4805,13 +5275,13 @@ wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev,
scan_done_out:
del_timer_sync(&wl->scan_timeout);
- flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
+ spin_lock_irqsave(&wl->cfgdrv_lock, flags);
if (wl->scan_request) {
WL_DBG(("cfg80211_scan_done\n"));
cfg80211_scan_done(wl->scan_request, false);
wl->scan_request = NULL;
}
- dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
+ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags);
mutex_unlock(&wl->usr_sync);
return err;
}
@@ -4867,7 +5337,10 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev,
bool isfree = false;
s32 err = 0;
s32 freq;
- wifi_p2p_pub_act_frame_t *act_frm;
+ struct net_device *dev = NULL;
+ wifi_p2p_pub_act_frame_t *act_frm = NULL;
+ wifi_p2p_action_frame_t *p2p_act_frm = NULL;
+ wifi_p2psd_gas_pub_act_frame_t *sd_act_frm = NULL;
wl_event_rx_frame_data_t *rxframe =
(wl_event_rx_frame_data_t*)data;
u32 event = ntoh32(e->event_type);
@@ -4877,22 +5350,32 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev,
u16 channel = ((ntoh16(rxframe->channel) & WL_CHANSPEC_CHAN_MASK));
memset(&bssid, 0, ETHER_ADDR_LEN);
+
+ if (wl->p2p_net == ndev) {
+ dev = wl_to_prmry_ndev(wl);
+ } else {
+ dev = ndev;
+ }
+
if (channel <= CH_MAX_2G_CHANNEL)
band = wiphy->bands[IEEE80211_BAND_2GHZ];
else
band = wiphy->bands[IEEE80211_BAND_5GHZ];
-
+ if (!band) {
+ WL_ERR(("No valid band"));
+ return -EINVAL;
+ }
#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
freq = ieee80211_channel_to_frequency(channel);
#else
freq = ieee80211_channel_to_frequency(channel, band->band);
#endif
if (event == WLC_E_ACTION_FRAME_RX) {
- wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
- NULL, 0, ioctlbuf, sizeof(ioctlbuf), bsscfgidx);
+ wldev_iovar_getbuf_bsscfg(dev, "cur_etheraddr",
+ NULL, 0, wl->ioctl_buf, WLC_IOCTL_MAXLEN, bsscfgidx, &wl->ioctl_buf_sync);
- wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false);
- memcpy(da.octet, ioctlbuf, ETHER_ADDR_LEN);
+ wldev_ioctl(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false);
+ memcpy(da.octet, wl->ioctl_buf, ETHER_ADDR_LEN);
err = wl_frame_get_mgmt(FC_ACTION, &da, &e->addr, &bssid,
&mgmt_frame, &mgmt_frame_len,
(u8 *)((wl_event_rx_frame_data_t *)rxframe + 1));
@@ -4902,13 +5385,29 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev,
goto exit;
}
isfree = true;
- act_frm =
- (wifi_p2p_pub_act_frame_t *) (&mgmt_frame[DOT11_MGMT_HDR_LEN]);
+ if (wl_cfgp2p_is_pub_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
+ mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
+ act_frm = (wifi_p2p_pub_act_frame_t *)
+ (&mgmt_frame[DOT11_MGMT_HDR_LEN]);
+ } else if (wl_cfgp2p_is_p2p_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
+ mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
+ p2p_act_frm = (wifi_p2p_action_frame_t *)
+ (&mgmt_frame[DOT11_MGMT_HDR_LEN]);
+ (void) p2p_act_frm;
+ } else if (wl_cfgp2p_is_gas_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
+ mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
+ sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)
+ (&mgmt_frame[DOT11_MGMT_HDR_LEN]);
+ (void) sd_act_frm;
+ }
+ wl_cfgp2p_print_actframe(false, &mgmt_frame[DOT11_MGMT_HDR_LEN],
+ mgmt_frame_len - DOT11_MGMT_HDR_LEN);
/*
* After complete GO Negotiation, roll back to mpc mode
*/
- if (act_frm->subtype == P2P_PAF_GON_CONF) {
- wldev_iovar_setint(ndev, "mpc", 1);
+ if (act_frm && ((act_frm->subtype == P2P_PAF_GON_CONF) ||
+ (act_frm->subtype == P2P_PAF_PROVDIS_RSP))) {
+ wldev_iovar_setint(dev, "mpc", 1);
}
} else {
mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1);
@@ -4925,14 +5424,122 @@ exit:
return 0;
}
+#ifdef WL_SCHED_SCAN
+/* If target scan is not reliable, set the below define to "1" to do a
+ * full escan
+ */
+#define FULL_ESCAN_ON_PFN_NET_FOUND 0
+static s32
+wl_notify_sched_scan_results(struct wl_priv *wl, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data)
+{
+ wl_pfn_net_info_t *netinfo, *pnetinfo;
+ struct cfg80211_scan_request request;
+ struct wiphy *wiphy = wl_to_wiphy(wl);
+ int err = 0;
+ struct cfg80211_ssid ssid[MAX_PFN_LIST_COUNT];
+ struct ieee80211_channel *channel = NULL;
+ int channel_req = 0;
+ int band = 0;
+ struct wl_pfn_scanresults *pfn_result = (struct wl_pfn_scanresults *)data;
+
+ WL_DBG(("Enter\n"));
+
+ if (e->event_type == WLC_E_PFN_NET_LOST) {
+ WL_DBG(("PFN NET LOST event. Do Nothing \n"));
+ return 0;
+ }
+ WL_DBG(("PFN NET FOUND event. count:%d \n", pfn_result->count));
+ if (pfn_result->count > 0) {
+ int i;
+
+ memset(&request, 0x00, sizeof(struct cfg80211_scan_request));
+ memset(&ssid, 0x00, sizeof(ssid));
+ request.wiphy = wiphy;
+
+ pnetinfo = (wl_pfn_net_info_t *)(data + sizeof(wl_pfn_scanresults_t)
+ - sizeof(wl_pfn_net_info_t));
+ channel = (struct ieee80211_channel *)kzalloc(
+ (sizeof(struct ieee80211_channel) * MAX_PFN_LIST_COUNT),
+ GFP_KERNEL);
+ if (!channel) {
+ WL_ERR(("No memory"));
+ err = -ENOMEM;
+ goto out_err;
+ }
+
+ for (i = 0; i < pfn_result->count; i++) {
+ netinfo = &pnetinfo[i];
+ if (!netinfo) {
+ WL_ERR(("Invalid netinfo ptr. index:%d", i));
+ err = -EINVAL;
+ goto out_err;
+ }
+ WL_DBG(("SSID:%s Channel:%d \n",
+ netinfo->pfnsubnet.SSID, netinfo->pfnsubnet.channel));
+ /* PFN result doesn't have all the info which are required by the supplicant
+ * (For e.g IEs) Do a target Escan so that sched scan results are reported
+ * via wl_inform_single_bss in the required format. Escan does require the
+ * scan request in the form of cfg80211_scan_request. For timebeing, create
+ * cfg80211_scan_request one out of the received PNO event.
+ */
+ memcpy(ssid[i].ssid, netinfo->pfnsubnet.SSID,
+ netinfo->pfnsubnet.SSID_len);
+ ssid[i].ssid_len = netinfo->pfnsubnet.SSID_len;
+ request.n_ssids++;
+
+ channel_req = netinfo->pfnsubnet.channel;
+ band = (channel_req <= CH_MAX_2G_CHANNEL) ? NL80211_BAND_2GHZ
+ : NL80211_BAND_5GHZ;
+ channel[i].center_freq = ieee80211_channel_to_frequency(channel_req, band);
+ channel[i].band = band;
+ channel[i].flags |= IEEE80211_CHAN_NO_HT40;
+ request.channels[i] = &channel[i];
+ request.n_channels++;
+ }
+
+ /* assign parsed ssid array */
+ if (request.n_ssids)
+ request.ssids = &ssid[0];
+
+ if (wl_get_drv_status_all(wl, SCANNING)) {
+ /* Abort any on-going scan */
+ wl_notify_escan_complete(wl, ndev, true, true);
+ }
+
+ if (wl_get_p2p_status(wl, DISCOVERY_ON)) {
+ err = wl_cfgp2p_discover_enable_search(wl, false);
+ if (unlikely(err)) {
+ wl_clr_drv_status(wl, SCANNING, ndev);
+ goto out_err;
+ }
+ }
+
+ wl_set_drv_status(wl, SCANNING, ndev);
+#if FULL_ESCAN_ON_PFN_NET_FOUND
+ err = wl_do_escan(wl, wiphy, ndev, NULL);
+#else
+ err = wl_do_escan(wl, wiphy, ndev, &request);
+#endif
+ if (err) {
+ wl_clr_drv_status(wl, SCANNING, ndev);
+ goto out_err;
+ }
+ wl->sched_scan_running = TRUE;
+ }
+ else {
+ WL_ERR(("FALSE PNO Event. (pfn_count == 0) \n"));
+ }
+out_err:
+ if (channel)
+ kfree(channel);
+ return err;
+}
+#endif /* WL_SCHED_SCAN */
+
static void wl_init_conf(struct wl_conf *conf)
{
- s32 i = 0;
WL_DBG(("Enter \n"));
- for (i = 0; i <= VWDEV_CNT; i++) {
- conf->mode[i].type = -1;
- conf->mode[i].ndev = NULL;
- }
conf->frag_threshold = (u32)-1;
conf->rts_threshold = (u32)-1;
conf->retry_short = (u32)-1;
@@ -4940,13 +5547,14 @@ static void wl_init_conf(struct wl_conf *conf)
conf->tx_power = -1;
}
-static void wl_init_prof(struct wl_priv *wl)
+static void wl_init_prof(struct wl_priv *wl, struct net_device *ndev)
{
unsigned long flags;
+ struct wl_profile *profile = wl_get_profile_by_netdev(wl, ndev);
- flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
- memset(wl->profile, 0, sizeof(struct wl_profile));
- dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
+ spin_lock_irqsave(&wl->cfgdrv_lock, flags);
+ memset(profile, 0, sizeof(struct wl_profile));
+ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags);
}
static void wl_init_event_handler(struct wl_priv *wl)
@@ -4969,7 +5577,9 @@ static void wl_init_event_handler(struct wl_priv *wl)
wl->evt_handler[WLC_E_P2P_DISC_LISTEN_COMPLETE] = wl_cfgp2p_listen_complete;
wl->evt_handler[WLC_E_ACTION_FRAME_COMPLETE] = wl_cfgp2p_action_tx_complete;
wl->evt_handler[WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE] = wl_cfgp2p_action_tx_complete;
-
+#ifdef PNO_SUPPORT
+ wl->evt_handler[WLC_E_PFN_NET_FOUND] = wl_notify_pfn_status;
+#endif /* PNO_SUPPORT */
}
static s32 wl_init_priv_mem(struct wl_priv *wl)
@@ -4985,23 +5595,13 @@ static s32 wl_init_priv_mem(struct wl_priv *wl)
WL_ERR(("wl_conf alloc failed\n"));
goto init_priv_mem_out;
}
- wl->profile = (void *)kzalloc(sizeof(*wl->profile), GFP_KERNEL);
- if (unlikely(!wl->profile)) {
- WL_ERR(("wl_profile alloc failed\n"));
- goto init_priv_mem_out;
- }
- wl->bss_info = (void *)kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
- if (unlikely(!wl->bss_info)) {
- WL_ERR(("Bss information alloc failed\n"));
- goto init_priv_mem_out;
- }
wl->scan_req_int =
(void *)kzalloc(sizeof(*wl->scan_req_int), GFP_KERNEL);
if (unlikely(!wl->scan_req_int)) {
WL_ERR(("Scan req alloc failed\n"));
goto init_priv_mem_out;
}
- wl->ioctl_buf = (void *)kzalloc(WL_IOCTL_LEN_MAX, GFP_KERNEL);
+ wl->ioctl_buf = (void *)kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL);
if (unlikely(!wl->ioctl_buf)) {
WL_ERR(("Ioctl buf alloc failed\n"));
goto init_priv_mem_out;
@@ -5021,11 +5621,6 @@ static s32 wl_init_priv_mem(struct wl_priv *wl)
WL_ERR(("Iscan buf alloc failed\n"));
goto init_priv_mem_out;
}
- wl->fw = (void *)kzalloc(sizeof(*wl->fw), GFP_KERNEL);
- if (unlikely(!wl->fw)) {
- WL_ERR(("fw object alloc failed\n"));
- goto init_priv_mem_out;
- }
wl->pmk_list = (void *)kzalloc(sizeof(*wl->pmk_list), GFP_KERNEL);
if (unlikely(!wl->pmk_list)) {
WL_ERR(("pmk list alloc failed\n"));
@@ -5036,6 +5631,14 @@ static s32 wl_init_priv_mem(struct wl_priv *wl)
WL_ERR(("sta info alloc failed\n"));
goto init_priv_mem_out;
}
+ wl->afx_hdl = (void *)kzalloc(sizeof(*wl->afx_hdl), GFP_KERNEL);
+ if (unlikely(!wl->afx_hdl)) {
+ WL_ERR(("afx hdl alloc failed\n"));
+ goto init_priv_mem_out;
+ } else {
+ init_completion(&wl->act_frm_scan);
+ INIT_WORK(&wl->afx_hdl->work, wl_cfg80211_afx_handler);
+ }
return 0;
init_priv_mem_out:
@@ -5048,12 +5651,8 @@ static void wl_deinit_priv_mem(struct wl_priv *wl)
{
kfree(wl->scan_results);
wl->scan_results = NULL;
- kfree(wl->bss_info);
- wl->bss_info = NULL;
kfree(wl->conf);
wl->conf = NULL;
- kfree(wl->profile);
- wl->profile = NULL;
kfree(wl->scan_req_int);
wl->scan_req_int = NULL;
kfree(wl->ioctl_buf);
@@ -5064,12 +5663,16 @@ static void wl_deinit_priv_mem(struct wl_priv *wl)
wl->extra_buf = NULL;
kfree(wl->iscan);
wl->iscan = NULL;
- kfree(wl->fw);
- wl->fw = NULL;
kfree(wl->pmk_list);
wl->pmk_list = NULL;
kfree(wl->sta_info);
wl->sta_info = NULL;
+ if (wl->afx_hdl) {
+ cancel_work_sync(&wl->afx_hdl->work);
+ kfree(wl->afx_hdl);
+ wl->afx_hdl = NULL;
+ }
+
if (wl->ap_info) {
kfree(wl->ap_info->wpa_ie);
kfree(wl->ap_info->rsn_ie);
@@ -5084,7 +5687,8 @@ static s32 wl_create_event_handler(struct wl_priv *wl)
int ret = 0;
WL_DBG(("Enter \n"));
- wl->event_tsk.thr_pid = DHD_PID_KT_INVALID;
+ /* Do not use DHD in cfg driver */
+ wl->event_tsk.thr_pid = -1;
PROC_START(wl_event_handler, wl, &wl->event_tsk, 0);
if (wl->event_tsk.thr_pid < 0)
ret = -ENOMEM;
@@ -5114,21 +5718,22 @@ static void wl_term_iscan(struct wl_priv *wl)
static void wl_notify_iscan_complete(struct wl_iscan_ctrl *iscan, bool aborted)
{
struct wl_priv *wl = iscan_to_wl(iscan);
+ struct net_device *ndev = wl_to_prmry_ndev(wl);
unsigned long flags;
WL_DBG(("Enter \n"));
- if (unlikely(!wl_get_drv_status(wl, SCANNING))) {
- wl_clr_drv_status(wl, SCANNING);
+ if (!wl_get_drv_status(wl, SCANNING, ndev)) {
+ wl_clr_drv_status(wl, SCANNING, ndev);
WL_ERR(("Scan complete while device not scanning\n"));
return;
}
- flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
- wl_clr_drv_status(wl, SCANNING);
+ spin_lock_irqsave(&wl->cfgdrv_lock, flags);
+ wl_clr_drv_status(wl, SCANNING, ndev);
if (likely(wl->scan_request)) {
cfg80211_scan_done(wl->scan_request, aborted);
wl->scan_request = NULL;
}
- dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
+ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags);
wl->iscan_kickstart = false;
}
@@ -5164,7 +5769,7 @@ wl_get_iscan_results(struct wl_iscan_ctrl *iscan, u32 *status,
list.results.buflen = htod32(WL_ISCAN_BUF_MAX);
err = wldev_iovar_getbuf(iscan->dev, "iscanresults", &list,
WL_ISCAN_RESULTS_FIXED_SIZE, iscan->scan_buf,
- WL_ISCAN_BUF_MAX);
+ WL_ISCAN_BUF_MAX, NULL);
if (unlikely(err)) {
WL_ERR(("error (%d)\n", err));
return err;
@@ -5237,13 +5842,11 @@ static s32 wl_iscan_aborted(struct wl_priv *wl)
static s32 wl_iscan_thread(void *data)
{
- struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1 };
struct wl_iscan_ctrl *iscan = (struct wl_iscan_ctrl *)data;
struct wl_priv *wl = iscan_to_wl(iscan);
u32 status;
int err = 0;
- sched_setscheduler(current, SCHED_FIFO, &param);
allow_signal(SIGTERM);
status = WL_SCAN_RESULTS_PARTIAL;
while (likely(!down_interruptible(&iscan->sync))) {
@@ -5278,7 +5881,7 @@ static void wl_scan_timeout(unsigned long data)
if (wl->scan_request) {
WL_ERR(("timer expired\n"));
if (wl->escan_on)
- wl_notify_escan_complete(wl, true);
+ wl_notify_escan_complete(wl, wl->escan_info.ndev, true, false);
else
wl_notify_iscan_complete(wl_to_iscan(wl), true);
}
@@ -5324,21 +5927,109 @@ static void wl_init_iscan_handler(struct wl_iscan_ctrl *iscan)
iscan->iscan_handler[WL_SCAN_RESULTS_NO_MEM] = wl_iscan_aborted;
}
-static void wl_notify_escan_complete(struct wl_priv *wl, bool aborted)
+static s32
+wl_cfg80211_netdev_notifier_call(struct notifier_block * nb,
+ unsigned long state,
+ void *ndev)
{
+ struct net_device *dev = ndev;
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct wl_priv *wl = wlcfg_drv_priv;
+
+ WL_DBG(("Enter \n"));
+ if (!wdev || !wl || dev == wl_to_prmry_ndev(wl))
+ return NOTIFY_DONE;
+ switch (state) {
+ case NETDEV_UNREGISTER:
+ /* after calling list_del_rcu(&wdev->list) */
+ wl_dealloc_netinfo(wl, ndev);
+ break;
+ case NETDEV_GOING_DOWN:
+ /* At NETDEV_DOWN state, wdev_cleanup_work work will be called.
+ * In front of door, the function checks
+ * whether current scan is working or not.
+ * If the scanning is still working, wdev_cleanup_work call WARN_ON and
+ * make the scan done forcibly.
+ */
+ if (wl_get_drv_status(wl, SCANNING, dev)) {
+ if (wl->escan_on) {
+ wl_notify_escan_complete(wl, dev, true, true);
+ }
+ }
+ break;
+ }
+ return NOTIFY_DONE;
+}
+static struct notifier_block wl_cfg80211_netdev_notifier = {
+ .notifier_call = wl_cfg80211_netdev_notifier_call,
+};
+
+static s32 wl_notify_escan_complete(struct wl_priv *wl,
+ struct net_device *ndev,
+ bool aborted, bool fw_abort)
+{
+ wl_scan_params_t *params = NULL;
+ s32 params_size = 0;
+ s32 err = BCME_OK;
unsigned long flags;
+ struct net_device *dev;
WL_DBG(("Enter \n"));
- wl_clr_drv_status(wl, SCANNING);
- if (wl->p2p_supported && p2p_on(wl))
- wl_clr_p2p_status(wl, SCANNING);
- flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
+ if (wl->scan_request) {
+ if (wl->scan_request->dev == wl->p2p_net)
+ dev = wl_to_prmry_ndev(wl);
+ else
+ dev = wl->scan_request->dev;
+ }
+ else {
+ WL_ERR(("wl->scan_request is NULL may be internal scan."
+ "doing scan_abort for ndev %p primary %p p2p_net %p",
+ ndev, wl_to_prmry_ndev(wl), wl->p2p_net));
+ dev = ndev;
+ }
+ if (fw_abort && !in_atomic()) {
+ /* Our scan params only need space for 1 channel and 0 ssids */
+ params = wl_cfg80211_scan_alloc_params(-1, 0, &params_size);
+ if (params == NULL) {
+ WL_ERR(("scan params allocation failed \n"));
+ err = -ENOMEM;
+ } else {
+ /* Do a scan abort to stop the driver's scan engine */
+ err = wldev_ioctl(dev, WLC_SCAN, params, params_size, true);
+ if (err < 0) {
+ WL_ERR(("scan abort failed \n"));
+ }
+ }
+ }
+ if (timer_pending(&wl->scan_timeout))
+ del_timer_sync(&wl->scan_timeout);
+ spin_lock_irqsave(&wl->cfgdrv_lock, flags);
+
+#ifdef WL_SCHED_SCAN
+ if (wl->sched_scan_req && !wl->scan_request) {
+ WL_DBG((" REPORTING SCHED SCAN RESULTS \n"));
+ if (aborted)
+ cfg80211_sched_scan_stopped(wl->sched_scan_req->wiphy);
+ else
+ cfg80211_sched_scan_results(wl->sched_scan_req->wiphy);
+ wl->sched_scan_running = FALSE;
+ wl->sched_scan_req = NULL;
+ }
+#endif /* WL_SCHED_SCAN */
+
if (likely(wl->scan_request)) {
cfg80211_scan_done(wl->scan_request, aborted);
wl->scan_request = NULL;
}
- dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
+ if (p2p_is_on(wl))
+ wl_clr_p2p_status(wl, SCANNING);
+ wl_clr_drv_status(wl, SCANNING, dev);
+ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags);
+ if (params)
+ kfree(params);
+
+ return err;
}
static s32 wl_escan_handler(struct wl_priv *wl,
@@ -5353,11 +6044,21 @@ static s32 wl_escan_handler(struct wl_priv *wl,
wl_scan_results_t *list;
u32 bi_length;
u32 i;
+
WL_DBG((" enter event type : %d, status : %d \n",
ntoh32(e->event_type), ntoh32(e->status)));
- if (!wl->escan_on &&
- !wl_get_drv_status(wl, SCANNING)) {
- WL_ERR(("escan is not ready \n"));
+ /* P2P SCAN is coming from primary interface */
+ if (wl_get_p2p_status(wl, SCANNING)) {
+ if (wl_get_drv_status_all(wl, SENDING_ACT_FRM))
+ ndev = wl->afx_hdl->dev;
+ else
+ ndev = wl->escan_info.ndev;
+
+ }
+ if (!ndev || !wl->escan_on ||
+ !wl_get_drv_status(wl, SCANNING, ndev)) {
+ WL_ERR(("escan is not ready ndev %p wl->escan_on %d drv_status 0x%x\n",
+ ndev, wl->escan_on, wl_get_drv_status(wl, SCANNING, ndev)));
return err;
}
@@ -5382,77 +6083,114 @@ static s32 wl_escan_handler(struct wl_priv *wl,
WL_ERR(("Invalid bss_info length %d: ignoring\n", bi_length));
goto exit;
}
- list = (wl_scan_results_t *)wl->escan_info.escan_buf;
- if (bi_length > ESCAN_BUF_SIZE - list->buflen) {
- WL_ERR(("Buffer is too small: ignoring\n"));
- goto exit;
+
+ if (!(wl_to_wiphy(wl)->interface_modes & BIT(NL80211_IFTYPE_ADHOC))) {
+ if (dtoh16(bi->capability) & DOT11_CAP_IBSS) {
+ WL_ERR(("Ignoring IBSS result\n"));
+ goto exit;
+ }
}
-#define WLC_BSS_RSSI_ON_CHANNEL 0x0002
- for (i = 0; i < list->count; i++) {
- bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length))
- : list->bss_info;
-
- if (!bcmp(&bi->BSSID, &bss->BSSID, ETHER_ADDR_LEN) &&
- CHSPEC_BAND(bi->chanspec) == CHSPEC_BAND(bss->chanspec) &&
- bi->SSID_len == bss->SSID_len &&
- !bcmp(bi->SSID, bss->SSID, bi->SSID_len)) {
- if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) ==
- (bi->flags & WLC_BSS_RSSI_ON_CHANNEL)) {
- /* preserve max RSSI if the measurements are
- * both on-channel or both off-channel
- */
- bss->RSSI = MAX(bss->RSSI, bi->RSSI);
- } else if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) &&
- (bi->flags & WLC_BSS_RSSI_ON_CHANNEL) == 0) {
- /* preserve the on-channel rssi measurement
- * if the new measurement is off channel
- */
- bss->RSSI = bi->RSSI;
- bss->flags |= WLC_BSS_RSSI_ON_CHANNEL;
- }
+ if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) {
+ if (!memcmp(bi->BSSID.octet,
+ wl->afx_hdl->pending_tx_dst_addr.octet, ETHER_ADDR_LEN)) {
+ s32 channel = CHSPEC_CHANNEL(dtohchanspec(bi->chanspec));
+ WL_DBG(("ACTION FRAME SCAN : Peer found, channel : %d\n", channel));
+ wl_clr_p2p_status(wl, SCANNING);
+ wl->afx_hdl->peer_chan = channel;
+ complete(&wl->act_frm_scan);
goto exit;
}
+
+ } else {
+ list = (wl_scan_results_t *)wl->escan_info.escan_buf;
+ if (bi_length > ESCAN_BUF_SIZE - list->buflen) {
+ WL_ERR(("Buffer is too small: ignoring\n"));
+ goto exit;
+ }
+#define WLC_BSS_RSSI_ON_CHANNEL 0x0002
+ for (i = 0; i < list->count; i++) {
+ bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length))
+ : list->bss_info;
+
+ if (!bcmp(&bi->BSSID, &bss->BSSID, ETHER_ADDR_LEN) &&
+ CHSPEC_BAND(bi->chanspec) == CHSPEC_BAND(bss->chanspec) &&
+ bi->SSID_len == bss->SSID_len &&
+ !bcmp(bi->SSID, bss->SSID, bi->SSID_len)) {
+ if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) ==
+ (bi->flags & WLC_BSS_RSSI_ON_CHANNEL)) {
+ /* preserve max RSSI if the measurements are
+ * both on-channel or both off-channel
+ */
+ bss->RSSI = MAX(bss->RSSI, bi->RSSI);
+ } else if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) &&
+ (bi->flags & WLC_BSS_RSSI_ON_CHANNEL) == 0) {
+ /* preserve the on-channel rssi measurement
+ * if the new measurement is off channel
+ */
+ bss->RSSI = bi->RSSI;
+ bss->flags |= WLC_BSS_RSSI_ON_CHANNEL;
+ }
+
+ goto exit;
+ }
+ }
+ memcpy(&(wl->escan_info.escan_buf[list->buflen]), bi, bi_length);
+ list->version = dtoh32(bi->version);
+ list->buflen += bi_length;
+ list->count++;
+
}
- memcpy(&(wl->escan_info.escan_buf[list->buflen]), bi, bi_length);
- list->version = dtoh32(bi->version);
- list->buflen += bi_length;
- list->count++;
}
else if (status == WLC_E_STATUS_SUCCESS) {
wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
- if (likely(wl->scan_request)) {
+ if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) {
+ WL_INFO(("ACTION FRAME SCAN DONE\n"));
+ wl_clr_p2p_status(wl, SCANNING);
+ wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev);
+ if (wl->afx_hdl->peer_chan == WL_INVALID)
+ complete(&wl->act_frm_scan);
+ } else if ((likely(wl->scan_request)) || (wl->sched_scan_running)) {
mutex_lock(&wl->usr_sync);
- del_timer_sync(&wl->scan_timeout);
WL_INFO(("ESCAN COMPLETED\n"));
wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf;
wl_inform_bss(wl);
- wl_notify_escan_complete(wl, false);
+ wl_notify_escan_complete(wl, ndev, false, false);
mutex_unlock(&wl->usr_sync);
}
}
else if (status == WLC_E_STATUS_ABORT) {
wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
- if (likely(wl->scan_request)) {
+ if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) {
+ WL_INFO(("ACTION FRAME SCAN DONE\n"));
+ wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev);
+ wl_clr_p2p_status(wl, SCANNING);
+ if (wl->afx_hdl->peer_chan == WL_INVALID)
+ complete(&wl->act_frm_scan);
+ } else if ((likely(wl->scan_request)) || (wl->sched_scan_running)) {
mutex_lock(&wl->usr_sync);
- del_timer_sync(&wl->scan_timeout);
WL_INFO(("ESCAN ABORTED\n"));
wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf;
wl_inform_bss(wl);
- wl_notify_escan_complete(wl, true);
+ wl_notify_escan_complete(wl, ndev, true, false);
mutex_unlock(&wl->usr_sync);
}
}
else {
WL_ERR(("unexpected Escan Event %d : abort\n", status));
wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
- if (likely(wl->scan_request)) {
+ if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) {
+ WL_INFO(("ACTION FRAME SCAN DONE\n"));
+ wl_clr_p2p_status(wl, SCANNING);
+ wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev);
+ if (wl->afx_hdl->peer_chan == WL_INVALID)
+ complete(&wl->act_frm_scan);
+ } else if ((likely(wl->scan_request)) || (wl->sched_scan_running)) {
mutex_lock(&wl->usr_sync);
- del_timer_sync(&wl->scan_timeout);
wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf;
wl_inform_bss(wl);
- wl_notify_escan_complete(wl, true);
+ wl_notify_escan_complete(wl, ndev, true, false);
mutex_unlock(&wl->usr_sync);
}
}
@@ -5493,16 +6231,11 @@ static s32 wl_init_scan(struct wl_priv *wl)
return err;
}
-static void wl_init_fw(struct wl_fw_ctrl *fw)
-{
- fw->status = 0;
-}
-
static s32 wl_init_priv(struct wl_priv *wl)
{
struct wiphy *wiphy = wl_to_wiphy(wl);
+ struct net_device *ndev = wl_to_prmry_ndev(wl);
s32 err = 0;
- s32 i = 0;
wl->scan_request = NULL;
wl->pwr_save = !!(wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT);
@@ -5511,60 +6244,78 @@ static s32 wl_init_priv(struct wl_priv *wl)
wl->roam_on = false;
wl->iscan_kickstart = false;
wl->active_scan = true;
- wl->dongle_up = false;
wl->rf_blocked = false;
-
- for (i = 0; i < VWDEV_CNT; i++)
- wl->vwdev[i] = NULL;
-
- init_waitqueue_head(&wl->dongle_event_wait);
+ wl->deauth_reason = 0;
+ spin_lock_init(&wl->cfgdrv_lock);
+ mutex_init(&wl->ioctl_buf_sync);
+ init_waitqueue_head(&wl->netif_change_event);
wl_init_eq(wl);
err = wl_init_priv_mem(wl);
- if (unlikely(err))
+ if (err)
return err;
- if (unlikely(wl_create_event_handler(wl)))
+ if (wl_create_event_handler(wl))
return -ENOMEM;
wl_init_event_handler(wl);
mutex_init(&wl->usr_sync);
err = wl_init_scan(wl);
- if (unlikely(err))
+ if (err)
return err;
- wl_init_fw(wl->fw);
wl_init_conf(wl->conf);
- wl_init_prof(wl);
+ wl_init_prof(wl, ndev);
wl_link_down(wl);
+ DNGL_FUNC(dhd_cfg80211_init, (wl));
return err;
}
static void wl_deinit_priv(struct wl_priv *wl)
{
+ DNGL_FUNC(dhd_cfg80211_deinit, (wl));
wl_destroy_event_handler(wl);
- wl->dongle_up = false; /* dongle down */
wl_flush_eq(wl);
wl_link_down(wl);
del_timer_sync(&wl->scan_timeout);
wl_term_iscan(wl);
wl_deinit_priv_mem(wl);
+ unregister_netdevice_notifier(&wl_cfg80211_netdev_notifier);
}
-#if defined(DHD_P2P_DEV_ADDR_FROM_SYSFS) && defined(CONFIG_SYSCTL)
-s32 wl_cfg80211_sysctl_export_devaddr(void *data)
+#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF)
+static s32 wl_cfg80211_attach_p2p(void)
+{
+ struct wl_priv *wl = wlcfg_drv_priv;
+
+ WL_TRACE(("Enter \n"));
+
+ if (wl_cfgp2p_register_ndev(wl) < 0) {
+ WL_ERR(("%s: P2P attach failed. \n", __func__));
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static s32 wl_cfg80211_detach_p2p(void)
{
- /* Export the p2p_dev_addr via sysctl interface
- * so that wpa_supplicant can access it
- */
- dhd_pub_t *dhd = (dhd_pub_t *)data;
struct wl_priv *wl = wlcfg_drv_priv;
+ struct wireless_dev *wdev = wl->p2p_wdev;
- wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr);
+ WL_DBG(("Enter \n"));
+ if (!wdev || !wl) {
+ WL_ERR(("Invalid Ptr\n"));
+ return -EINVAL;
+ }
- sprintf((char *)&wl_sysctl_macstring[0], MACSTR, MAC2STR(wl->p2p->dev_addr.octet));
- sprintf((char *)&wl_sysctl_macstring[1], MACSTR, MAC2STR(wl->p2p->int_addr.octet));
+ wl_cfgp2p_unregister_ndev(wl);
+
+ wl->p2p_wdev = NULL;
+ wl->p2p_net = NULL;
+ WL_DBG(("Freeing 0x%08x \n", (unsigned int)wdev));
+ kfree(wdev);
return 0;
}
-#endif /* CONFIG_SYSCTL */
+#endif /* defined(WLP2P) && defined(WL_ENABLE_P2P_IF) */
s32 wl_cfg80211_attach_post(struct net_device *ndev)
{
@@ -5576,75 +6327,107 @@ s32 wl_cfg80211_attach_post(struct net_device *ndev)
return -ENODEV;
}
wl = wlcfg_drv_priv;
- if (wl && !wl_get_drv_status(wl, READY)) {
+ if (wl && !wl_get_drv_status(wl, READY, ndev)) {
if (wl->wdev &&
wl_cfgp2p_supported(wl, ndev)) {
+#if !defined(WL_ENABLE_P2P_IF)
wl->wdev->wiphy->interface_modes |=
(BIT(NL80211_IFTYPE_P2P_CLIENT)|
BIT(NL80211_IFTYPE_P2P_GO));
+#endif
if ((err = wl_cfgp2p_init_priv(wl)) != 0)
goto fail;
-#if defined(DHD_P2P_DEV_ADDR_FROM_SYSFS) && defined(CONFIG_SYSCTL)
- wl_cfg80211_sysctl_export_devaddr(wl->pub);
-#endif
+
+#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF)
+ if (wl->p2p_net) {
+ /* Update MAC addr for p2p0 interface here. */
+ memcpy(wl->p2p_net->dev_addr, ndev->dev_addr, ETH_ALEN);
+ wl->p2p_net->dev_addr[0] |= 0x02;
+ printk("%s: p2p_dev_addr="MACSTR "\n",
+ wl->p2p_net->name, MAC2STR(wl->p2p_net->dev_addr));
+ } else {
+ WL_ERR(("p2p_net not yet populated."
+ " Couldn't update the MAC Address for p2p0 \n"));
+ return -ENODEV;
+ }
+#endif /* defined(WLP2P) && (WL_ENABLE_P2P_IF) */
+
wl->p2p_supported = true;
}
} else
return -ENODEV;
-
- wl_set_drv_status(wl, READY);
+ wl_set_drv_status(wl, READY, ndev);
fail:
return err;
}
+
s32 wl_cfg80211_attach(struct net_device *ndev, void *data)
{
struct wireless_dev *wdev;
struct wl_priv *wl;
s32 err = 0;
+ struct device *dev;
WL_TRACE(("In\n"));
- if (unlikely(!ndev)) {
+ if (!ndev) {
WL_ERR(("ndev is invaild\n"));
return -ENODEV;
}
- WL_DBG(("func %p\n", wl_cfg80211_get_sdio_func()));
- wdev = wl_alloc_wdev(&wl_cfg80211_get_sdio_func()->dev);
- if (unlikely(IS_ERR(wdev)))
- return -ENOMEM;
+ WL_DBG(("func %p\n", wl_cfg80211_get_parent_dev()));
+ dev = wl_cfg80211_get_parent_dev();
+ wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
+ if (unlikely(!wdev)) {
+ WL_ERR(("Could not allocate wireless device\n"));
+ return -ENOMEM;
+ }
+ err = wl_setup_wiphy(wdev, dev);
+ if (unlikely(err)) {
+ kfree(wdev);
+ return -ENOMEM;
+ }
wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS);
wl = (struct wl_priv *)wiphy_priv(wdev->wiphy);
wl->wdev = wdev;
wl->pub = data;
-
+ INIT_LIST_HEAD(&wl->net_list);
ndev->ieee80211_ptr = wdev;
SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
wdev->netdev = ndev;
-
+ err = wl_alloc_netinfo(wl, ndev, wdev, WL_MODE_BSS);
+ if (err) {
+ WL_ERR(("Failed to alloc net_info (%d)\n", err));
+ goto cfg80211_attach_out;
+ }
err = wl_init_priv(wl);
- if (unlikely(err)) {
+ if (err) {
WL_ERR(("Failed to init iwm_priv (%d)\n", err));
goto cfg80211_attach_out;
}
err = wl_setup_rfkill(wl, TRUE);
- if (unlikely(err)) {
+ if (err) {
WL_ERR(("Failed to setup rfkill %d\n", err));
goto cfg80211_attach_out;
}
-
-#if defined(DHD_P2P_DEV_ADDR_FROM_SYSFS) && defined(CONFIG_SYSCTL)
- if (!(wl_sysctl_hdr = register_sysctl_table(wl_sysctl_table))) {
- WL_ERR(("%s: sysctl register failed!! \n", __func__));
+ err = register_netdevice_notifier(&wl_cfg80211_netdev_notifier);
+ if (err) {
+ WL_ERR(("Failed to register notifierl %d\n", err));
goto cfg80211_attach_out;
}
-#endif
#if defined(COEX_DHCP)
if (wl_cfg80211_btcoex_init(wl))
goto cfg80211_attach_out;
-#endif /* COEX_DHCP */
+#endif
wlcfg_drv_priv = wl;
+
+#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF)
+ err = wl_cfg80211_attach_p2p();
+ if (err)
+ goto cfg80211_attach_out;
+#endif
+
return err;
cfg80211_attach_out:
@@ -5653,7 +6436,7 @@ cfg80211_attach_out:
return err;
}
-void wl_cfg80211_detach(void)
+void wl_cfg80211_detach(void *para)
{
struct wl_priv *wl;
@@ -5663,19 +6446,21 @@ void wl_cfg80211_detach(void)
#if defined(COEX_DHCP)
wl_cfg80211_btcoex_deinit(wl);
-#endif /* COEX_DHCP */
+#endif
-#if defined(DHD_P2P_DEV_ADDR_FROM_SYSFS) && defined(CONFIG_SYSCTL)
- if (wl_sysctl_hdr)
- unregister_sysctl_table(wl_sysctl_hdr);
+#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF)
+ wl_cfg80211_detach_p2p();
#endif
wl_setup_rfkill(wl, FALSE);
if (wl->p2p_supported)
wl_cfgp2p_deinit_priv(wl);
wl_deinit_priv(wl);
wlcfg_drv_priv = NULL;
- wl_clear_sdio_func();
+ wl_cfg80211_clear_parent_dev();
wl_free_wdev(wl);
+ /* PLEASE do NOT call any function after wl_free_wdev, the driver's private structure "wl",
+ * which is the private part of wiphy, has been freed in wl_free_wdev !!!!!!!!!!!
+ */
}
static void wl_wakeup_event(struct wl_priv *wl)
@@ -5686,6 +6471,42 @@ static void wl_wakeup_event(struct wl_priv *wl)
}
}
+static int wl_is_p2p_event(struct wl_event_q *e)
+{
+ switch (e->etype) {
+ /* We have to seperate out the P2P events received
+ * on primary interface so that it can be send up
+ * via p2p0 interface.
+ */
+ case WLC_E_P2P_PROBREQ_MSG:
+ case WLC_E_P2P_DISC_LISTEN_COMPLETE:
+ case WLC_E_ACTION_FRAME_RX:
+ case WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE:
+ case WLC_E_ACTION_FRAME_COMPLETE:
+
+ if (e->emsg.ifidx != 0) {
+ WL_TRACE(("P2P Event on Virtual I/F (ifidx:%d) \n",
+ e->emsg.ifidx));
+ /* We are only bothered about the P2P events received
+ * on primary interface. For rest of them return false
+ * so that it is sent over the interface corresponding
+ * to the ifidx.
+ */
+ return FALSE;
+ } else {
+ WL_TRACE(("P2P Event on Primary I/F (ifidx:%d)."
+ " Sent it to p2p0 \n", e->emsg.ifidx));
+ return TRUE;
+ }
+ break;
+
+ default:
+ WL_TRACE(("NON-P2P Event %d on ifidx (ifidx:%d) \n",
+ e->etype, e->emsg.ifidx));
+ return FALSE;
+ }
+}
+
static s32 wl_event_handler(void *data)
{
struct net_device *netdev;
@@ -5694,6 +6515,7 @@ static s32 wl_event_handler(void *data)
tsk_ctl_t *tsk = (tsk_ctl_t *)data;
wl = (struct wl_priv *)tsk->parent;
+ DAEMONIZE("dhd_cfg80211_event");
complete(&tsk->completed);
while (down_interruptible (&tsk->sema) == 0) {
@@ -5702,7 +6524,15 @@ static s32 wl_event_handler(void *data)
break;
while ((e = wl_deq_event(wl))) {
WL_DBG(("event type (%d), if idx: %d\n", e->etype, e->emsg.ifidx));
- netdev = dhd_idx2net((struct dhd_pub *)(wl->pub), e->emsg.ifidx);
+ /* All P2P device address related events comes on primary interface since
+ * there is no corresponding bsscfg for P2P interface. Map it to p2p0
+ * interface.
+ */
+ if ((wl_is_p2p_event(e) == TRUE) && (wl->p2p_net)) {
+ netdev = wl->p2p_net;
+ } else {
+ netdev = dhd_idx2net((struct dhd_pub *)(wl->pub), e->emsg.ifidx);
+ }
if (!netdev)
netdev = wl_to_prmry_ndev(wl);
if (e->etype < WLC_E_LAST && wl->evt_handler[e->etype]) {
@@ -5714,7 +6544,7 @@ static s32 wl_event_handler(void *data)
}
DHD_OS_WAKE_UNLOCK(wl->pub);
}
- WL_DBG(("%s was terminated\n", __func__));
+ WL_ERR(("%s was terminated\n", __func__));
complete_and_exit(&tsk->completed, 0);
return 0;
}
@@ -5731,9 +6561,6 @@ wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data)
WL_DBG(("event_type (%d):" "WLC_E_" "%s\n", event_type, estr));
#endif /* (WL_DBG_LEVEL > 0) */
- if (event_type == WLC_E_PFN_NET_FOUND)
- WL_ERR((" PNO Event\n"));
-
if (likely(!wl_enq_event(wl, ndev, event_type, e, data)))
wl_wakeup_event(wl);
}
@@ -5818,22 +6645,7 @@ static void wl_put_event(struct wl_event_q *e)
kfree(e);
}
-void wl_cfg80211_set_sdio_func(void *func)
-{
- cfg80211_sdio_func = (struct sdio_func *)func;
-}
-
-static void wl_clear_sdio_func(void)
-{
- cfg80211_sdio_func = NULL;
-}
-
-struct sdio_func *wl_cfg80211_get_sdio_func(void)
-{
- return cfg80211_sdio_func;
-}
-
-static s32 wl_dongle_mode(struct wl_priv *wl, struct net_device *ndev, s32 iftype)
+static s32 wl_config_ifmode(struct wl_priv *wl, struct net_device *ndev, s32 iftype)
{
s32 infra = 0;
s32 err = 0;
@@ -5870,11 +6682,12 @@ static s32 wl_dongle_mode(struct wl_priv *wl, struct net_device *ndev, s32 iftyp
return err;
}
- set_mode_by_netdev(wl, ndev, mode);
+ wl_set_mode_by_netdev(wl, ndev, mode);
return 0;
}
-static s32 wl_dongle_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add)
+
+static s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add)
{
s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
@@ -5887,7 +6700,7 @@ static s32 wl_dongle_add_remove_eventmsg(struct net_device *ndev, u16 event, boo
err = wldev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf), false);
if (unlikely(err)) {
WL_ERR(("Get event_msgs error (%d)\n", err));
- goto dongle_eventmsg_out;
+ goto eventmsg_out;
}
memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN);
if (add) {
@@ -5900,389 +6713,103 @@ static s32 wl_dongle_add_remove_eventmsg(struct net_device *ndev, u16 event, boo
err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
if (unlikely(err)) {
WL_ERR(("Set event_msgs error (%d)\n", err));
- goto dongle_eventmsg_out;
+ goto eventmsg_out;
}
-dongle_eventmsg_out:
+eventmsg_out:
return err;
}
-
-#ifndef EMBEDDED_PLATFORM
-static s32 wl_dongle_country(struct net_device *ndev, u8 ccode)
-{
-
- s32 err = 0;
-
- return err;
-}
-
-static s32 wl_dongle_up(struct net_device *ndev, u32 up)
-{
- s32 err = 0;
-
- err = wldev_ioctl(ndev, WLC_UP, &up, sizeof(up), true);
- if (unlikely(err)) {
- WL_ERR(("WLC_UP error (%d)\n", err));
- }
- return err;
-}
-
-static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode)
+s32 wl_update_wiphybands(struct wl_priv *wl)
{
+ struct wiphy *wiphy;
+ u32 bandlist[3];
+ u32 nband = 0;
+ u32 i = 0;
s32 err = 0;
-
- WL_TRACE(("In\n"));
- err = wldev_ioctl(ndev, WLC_SET_PM, &power_mode, sizeof(power_mode), true);
+ int nmode = 0;
+ int bw_40 = 0;
+ int index = 0;
+
+ WL_DBG(("Entry"));
+ memset(bandlist, 0, sizeof(bandlist));
+ err = wldev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_BANDLIST, bandlist,
+ sizeof(bandlist), false);
if (unlikely(err)) {
- WL_ERR(("WLC_SET_PM error (%d)\n", err));
+ WL_ERR(("error read bandlist (%d)\n", err));
+ return err;
}
- return err;
-}
-
-static s32
-wl_dongle_glom(struct net_device *ndev, u32 glom, u32 dongle_align)
-{
- s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
-
- s32 err = 0;
+ wiphy = wl_to_wiphy(wl);
+ nband = bandlist[0];
+ wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
+ wiphy->bands[IEEE80211_BAND_5GHZ] = NULL;
- /* Match Host and Dongle rx alignment */
- bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf,
- sizeof(iovbuf));
- err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
+ err = wldev_iovar_getint(wl_to_prmry_ndev(wl), "nmode", &nmode);
if (unlikely(err)) {
- WL_ERR(("txglomalign error (%d)\n", err));
- goto dongle_glom_out;
+ WL_ERR(("error reading nmode (%d)\n", err));
}
- /* disable glom option per default */
- bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
- err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
- if (unlikely(err)) {
- WL_ERR(("txglom error (%d)\n", err));
- goto dongle_glom_out;
- }
-dongle_glom_out:
- return err;
-}
-
-static s32
-wl_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
-{
- s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
-
- s32 err = 0;
-
- /* Setup timeout if Beacons are lost and roam is off to report link down */
- if (roamvar) {
- bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf,
- sizeof(iovbuf));
- err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
+ else {
+ /* For nmodeonly check bw cap */
+ err = wldev_iovar_getint(wl_to_prmry_ndev(wl), "mimo_bw_cap", &bw_40);
if (unlikely(err)) {
- WL_ERR(("bcn_timeout error (%d)\n", err));
- goto dongle_rom_out;
+ WL_ERR(("error get mimo_bw_cap (%d)\n", err));
}
}
- /* Enable/Disable built-in roaming to allow supplicant to take care of roaming */
- bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
- err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
- if (unlikely(err)) {
- WL_ERR(("roam_off error (%d)\n", err));
- goto dongle_rom_out;
- }
-dongle_rom_out:
- return err;
-}
-static s32
-wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
- s32 scan_unassoc_time)
-{
- s32 err = 0;
-
- err = wldev_ioctl(ndev, WLC_SET_SCAN_CHANNEL_TIME, &scan_assoc_time,
- sizeof(scan_assoc_time), true);
- if (err) {
- if (err == -EOPNOTSUPP) {
- WL_INFO(("Scan assoc time is not supported\n"));
- } else {
- WL_ERR(("Scan assoc time error (%d)\n", err));
- }
- goto dongle_scantime_out;
- }
- err = wldev_ioctl(ndev, WLC_SET_SCAN_UNASSOC_TIME, &scan_unassoc_time,
- sizeof(scan_unassoc_time), true);
- if (err) {
- if (err == -EOPNOTSUPP) {
- WL_INFO(("Scan unassoc time is not supported\n"));
- } else {
- WL_ERR(("Scan unassoc time error (%d)\n", err));
+ for (i = 1; i <= nband && i < sizeof(bandlist)/sizeof(u32); i++) {
+ index = -1;
+ if (bandlist[i] == WLC_BAND_5G) {
+ wiphy->bands[IEEE80211_BAND_5GHZ] =
+ &__wl_band_5ghz_a;
+ index = IEEE80211_BAND_5GHZ;
+ } else if (bandlist[i] == WLC_BAND_2G) {
+ wiphy->bands[IEEE80211_BAND_2GHZ] =
+ &__wl_band_2ghz;
+ index = IEEE80211_BAND_2GHZ;
}
- goto dongle_scantime_out;
- }
-
-dongle_scantime_out:
- return err;
-}
-
-static s32
-wl_dongle_offload(struct net_device *ndev, s32 arpoe, s32 arp_ol)
-{
- /* Room for "event_msgs" + '\0' + bitvec */
- s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
-
- s32 err = 0;
-
- /* Set ARP offload */
- bcm_mkiovar("arpoe", (char *)&arpoe, 4, iovbuf, sizeof(iovbuf));
- err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
- if (err) {
- if (err == -EOPNOTSUPP)
- WL_INFO(("arpoe is not supported\n"));
- else
- WL_ERR(("arpoe error (%d)\n", err));
-
- goto dongle_offload_out;
- }
- bcm_mkiovar("arp_ol", (char *)&arp_ol, 4, iovbuf, sizeof(iovbuf));
- err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
- if (err) {
- if (err == -EOPNOTSUPP)
- WL_INFO(("arp_ol is not supported\n"));
- else
- WL_ERR(("arp_ol error (%d)\n", err));
-
- goto dongle_offload_out;
- }
-
-dongle_offload_out:
- return err;
-}
-
-static s32 wl_pattern_atoh(s8 *src, s8 *dst)
-{
- int i;
- if (strncmp(src, "0x", 2) != 0 && strncmp(src, "0X", 2) != 0) {
- WL_ERR(("Mask invalid format. Needs to start with 0x\n"));
- return -1;
- }
- src = src + 2; /* Skip past 0x */
- if (strlen(src) % 2 != 0) {
- WL_ERR(("Mask invalid format. Needs to be of even length\n"));
- return -1;
- }
- for (i = 0; *src != '\0'; i++) {
- char num[3];
- strncpy(num, src, 2);
- num[2] = '\0';
- dst[i] = (u8) simple_strtoul(num, NULL, 16);
- src += 2;
- }
- return i;
-}
-
-static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode)
-{
- /* Room for "event_msgs" + '\0' + bitvec */
- s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
-
- const s8 *str;
- struct wl_pkt_filter pkt_filter;
- struct wl_pkt_filter *pkt_filterp;
- s32 buf_len;
- s32 str_len;
- u32 mask_size;
- u32 pattern_size;
- s8 buf[256];
- s32 err = 0;
-
- /* add a default packet filter pattern */
- str = "pkt_filter_add";
- str_len = strlen(str);
- strncpy(buf, str, str_len);
- buf[str_len] = '\0';
- buf_len = str_len + 1;
-
- pkt_filterp = (struct wl_pkt_filter *)(buf + str_len + 1);
-
- /* Parse packet filter id. */
- pkt_filter.id = htod32(100);
-
- /* Parse filter polarity. */
- pkt_filter.negate_match = htod32(0);
-
- /* Parse filter type. */
- pkt_filter.type = htod32(0);
-
- /* Parse pattern filter offset. */
- pkt_filter.u.pattern.offset = htod32(0);
-
- /* Parse pattern filter mask. */
- mask_size = htod32(wl_pattern_atoh("0xff",
- (char *)pkt_filterp->u.pattern.
- mask_and_pattern));
-
- /* Parse pattern filter pattern. */
- pattern_size = htod32(wl_pattern_atoh("0x00",
- (char *)&pkt_filterp->u.pattern.mask_and_pattern[mask_size]));
-
- if (mask_size != pattern_size) {
- WL_ERR(("Mask and pattern not the same size\n"));
- err = -EINVAL;
- goto dongle_filter_out;
- }
-
- pkt_filter.u.pattern.size_bytes = mask_size;
- buf_len += WL_PKT_FILTER_FIXED_LEN;
- buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size);
-
- /* Keep-alive attributes are set in local
- * variable (keep_alive_pkt), and
- * then memcpy'ed into buffer (keep_alive_pktp) since there is no
- * guarantee that the buffer is properly aligned.
- */
- memcpy((char *)pkt_filterp, &pkt_filter,
- WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN);
-
- err = wldev_ioctl(ndev, WLC_SET_VAR, buf, buf_len, true);
- if (err) {
- if (err == -EOPNOTSUPP) {
- WL_INFO(("filter not supported\n"));
- } else {
- WL_ERR(("filter (%d)\n", err));
+ if ((index >= 0) && nmode) {
+ wiphy->bands[index]->ht_cap.cap =
+ IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_DSSSCCK40 |
+ IEEE80211_HT_CAP_MAX_AMSDU;
+ wiphy->bands[index]->ht_cap.ht_supported = TRUE;
+ wiphy->bands[index]->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
+ wiphy->bands[index]->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
}
- goto dongle_filter_out;
- }
- /* set mode to allow pattern */
- bcm_mkiovar("pkt_filter_mode", (char *)&filter_mode, 4, iovbuf,
- sizeof(iovbuf));
- err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
- if (err) {
- if (err == -EOPNOTSUPP) {
- WL_INFO(("filter_mode not supported\n"));
- } else {
- WL_ERR(("filter_mode (%d)\n", err));
+ if ((index >= 0) && bw_40) {
+ wiphy->bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
}
- goto dongle_filter_out;
}
-dongle_filter_out:
+ wiphy_apply_custom_regulatory(wiphy, &brcm_regdom);
return err;
}
-#endif /* !EMBEDDED_PLATFORM */
-s32 wl_config_dongle(struct wl_priv *wl, bool need_lock)
+static s32 __wl_cfg80211_up(struct wl_priv *wl)
{
-#ifndef DHD_SDALIGN
-#define DHD_SDALIGN 32
-#endif
- struct net_device *ndev;
- struct wireless_dev *wdev;
s32 err = 0;
+ struct net_device *ndev = wl_to_prmry_ndev(wl);
+ struct wireless_dev *wdev = ndev->ieee80211_ptr;
- WL_TRACE(("In\n"));
- if (wl->dongle_up) {
- WL_ERR(("Dongle is already up\n"));
- return err;
- }
+ WL_DBG(("In\n"));
- ndev = wl_to_prmry_ndev(wl);
- wdev = ndev->ieee80211_ptr;
- if (need_lock)
- rtnl_lock();
-#ifndef EMBEDDED_PLATFORM
- err = wl_dongle_up(ndev, 0);
- if (unlikely(err)) {
- WL_ERR(("wl_dongle_up failed\n"));
- goto default_conf_out;
- }
- err = wl_dongle_country(ndev, 0);
- if (unlikely(err)) {
- WL_ERR(("wl_dongle_country failed\n"));
- goto default_conf_out;
- }
- err = wl_dongle_power(ndev, PM_FAST);
- if (unlikely(err)) {
- WL_ERR(("wl_dongle_power failed\n"));
- goto default_conf_out;
- }
- err = wl_dongle_glom(ndev, 0, DHD_SDALIGN);
- if (unlikely(err)) {
- WL_ERR(("wl_dongle_glom failed\n"));
- goto default_conf_out;
- }
- err = wl_dongle_roam(ndev, (wl->roam_on ? 0 : 1), 3);
- if (unlikely(err)) {
- WL_ERR(("wl_dongle_roam failed\n"));
- goto default_conf_out;
- }
- wl_dongle_scantime(ndev, 40, 80);
- wl_dongle_offload(ndev, 1, 0xf);
- wl_dongle_filter(ndev, 1);
-#endif /* !EMBEDDED_PLATFORM */
+ err = dhd_config_dongle(wl, false);
+ if (unlikely(err))
+ return err;
- err = wl_dongle_mode(wl, ndev, wdev->iftype);
+ err = wl_config_ifmode(wl, ndev, wdev->iftype);
if (unlikely(err && err != -EINPROGRESS)) {
- WL_ERR(("wl_dongle_mode failed\n"));
- goto default_conf_out;
+ WL_ERR(("wl_config_ifmode failed\n"));
}
- err = wl_dongle_probecap(wl);
- if (unlikely(err)) {
- WL_ERR(("wl_dongle_probecap failed\n"));
- goto default_conf_out;
- }
-
- /* -EINPROGRESS: Call commit handler */
-
-default_conf_out:
- if (need_lock)
- rtnl_unlock();
-
- wl->dongle_up = true;
-
- return err;
-
-}
-
-static s32 wl_update_wiphybands(struct wl_priv *wl)
-{
- struct wiphy *wiphy;
- s8 phylist_buf[128];
- s8 *phy;
- s32 err = 0;
-
- err = wldev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_PHYLIST, phylist_buf,
- sizeof(phylist_buf), false);
+ err = wl_update_wiphybands(wl);
if (unlikely(err)) {
- WL_ERR(("error (%d)\n", err));
- return err;
+ WL_ERR(("wl_update_wiphybands failed\n"));
}
- phy = phylist_buf;
- for (; *phy; phy++) {
- if (*phy == 'a' || *phy == 'n') {
- wiphy = wl_to_wiphy(wl);
- wiphy->bands[IEEE80211_BAND_5GHZ] =
- &__wl_band_5ghz_a;
- }
- }
- return err;
-}
-
-static s32 __wl_cfg80211_up(struct wl_priv *wl)
-{
- s32 err = 0;
-
- WL_TRACE(("In\n"));
- wl_debugfs_add_netdev_params(wl);
- err = wl_config_dongle(wl, false);
- if (unlikely(err))
- return err;
- dhd_monitor_init(wl->pub);
- wl_invoke_iscan(wl);
- wl_set_drv_status(wl, READY);
+ err = dhd_monitor_init(wl->pub);
+ err = wl_invoke_iscan(wl);
+ wl_set_drv_status(wl, READY, ndev);
return err;
}
@@ -6290,52 +6817,65 @@ static s32 __wl_cfg80211_down(struct wl_priv *wl)
{
s32 err = 0;
unsigned long flags;
+ struct net_info *iter, *next;
+ struct net_device *ndev = wl_to_prmry_ndev(wl);
+#ifdef WL_ENABLE_P2P_IF
+ struct wiphy *wiphy = wl_to_prmry_ndev(wl)->ieee80211_ptr->wiphy;
+ struct net_device *p2p_net = wl->p2p_net;
+#endif
- WL_TRACE(("In\n"));
+ WL_DBG(("In\n"));
/* Check if cfg80211 interface is already down */
- if (!wl_get_drv_status(wl, READY))
+ if (!wl_get_drv_status(wl, READY, ndev))
return err; /* it is even not ready */
-
- wl_set_drv_status(wl, SCAN_ABORTING);
+ for_each_ndev(wl, iter, next)
+ wl_set_drv_status(wl, SCAN_ABORTING, iter->ndev);
wl_term_iscan(wl);
- flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
+ spin_lock_irqsave(&wl->cfgdrv_lock, flags);
if (wl->scan_request) {
cfg80211_scan_done(wl->scan_request, true);
wl->scan_request = NULL;
}
- wl_clr_drv_status(wl, READY);
- wl_clr_drv_status(wl, SCANNING);
- wl_clr_drv_status(wl, SCAN_ABORTING);
- wl_clr_drv_status(wl, CONNECTING);
- wl_clr_drv_status(wl, CONNECTED);
- wl_clr_drv_status(wl, DISCONNECTING);
- if (wl_get_drv_status(wl, AP_CREATED)) {
- wl_clr_drv_status(wl, AP_CREATED);
- wl_clr_drv_status(wl, AP_CREATING);
+ for_each_ndev(wl, iter, next) {
+ wl_clr_drv_status(wl, READY, iter->ndev);
+ wl_clr_drv_status(wl, SCANNING, iter->ndev);
+ wl_clr_drv_status(wl, SCAN_ABORTING, iter->ndev);
+ wl_clr_drv_status(wl, CONNECTING, iter->ndev);
+ wl_clr_drv_status(wl, CONNECTED, iter->ndev);
+ wl_clr_drv_status(wl, DISCONNECTING, iter->ndev);
+ wl_clr_drv_status(wl, AP_CREATED, iter->ndev);
+ wl_clr_drv_status(wl, AP_CREATING, iter->ndev);
}
wl_to_prmry_ndev(wl)->ieee80211_ptr->iftype =
NL80211_IFTYPE_STATION;
- dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
-
- wl->dongle_up = false;
+#ifdef WL_ENABLE_P2P_IF
+ wiphy->interface_modes = (wiphy->interface_modes)
+ & (~(BIT(NL80211_IFTYPE_P2P_CLIENT)|
+ BIT(NL80211_IFTYPE_P2P_GO)));
+ if ((p2p_net) && (p2p_net->flags & IFF_UP)) {
+ /* p2p0 interface is still UP. Bring it down */
+ p2p_net->flags &= ~IFF_UP;
+ }
+#endif /* WL_ENABLE_P2P_IF */
+ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags);
+
+ DNGL_FUNC(dhd_cfg80211_down, (wl));
wl_flush_eq(wl);
wl_link_down(wl);
if (wl->p2p_supported)
wl_cfgp2p_down(wl);
dhd_monitor_uninit();
- wl_debugfs_remove_netdev(wl);
-
return err;
}
-s32 wl_cfg80211_up(void)
+s32 wl_cfg80211_up(void *para)
{
struct wl_priv *wl;
s32 err = 0;
- WL_TRACE(("In\n"));
+ WL_DBG(("In\n"));
wl = wlcfg_drv_priv;
mutex_lock(&wl->usr_sync);
wl_cfg80211_attach_post(wl_to_prmry_ndev(wl));
@@ -6343,17 +6883,16 @@ s32 wl_cfg80211_up(void)
if (err)
WL_ERR(("__wl_cfg80211_up failed\n"));
mutex_unlock(&wl->usr_sync);
-
return err;
}
-/* Private Event to Supplicant with indication that FW hangs */
+/* Private Event to Supplicant with indication that chip hangs */
int wl_cfg80211_hang(struct net_device *dev, u16 reason)
{
struct wl_priv *wl;
wl = wlcfg_drv_priv;
- WL_ERR(("In : FW crash Eventing\n"));
+ WL_ERR(("In : chip crash eventing\n"));
cfg80211_disconnected(dev, reason, NULL, 0, GFP_KERNEL);
if (wl != NULL) {
wl_link_down(wl);
@@ -6361,12 +6900,12 @@ int wl_cfg80211_hang(struct net_device *dev, u16 reason)
return 0;
}
-s32 wl_cfg80211_down(void)
+s32 wl_cfg80211_down(void *para)
{
struct wl_priv *wl;
s32 err = 0;
- WL_TRACE(("In\n"));
+ WL_DBG(("In\n"));
wl = wlcfg_drv_priv;
mutex_lock(&wl->usr_sync);
err = __wl_cfg80211_down(wl);
@@ -6375,84 +6914,79 @@ s32 wl_cfg80211_down(void)
return err;
}
-static s32 wl_dongle_probecap(struct wl_priv *wl)
-{
- s32 err = 0;
-
- err = wl_update_wiphybands(wl);
- if (unlikely(err))
- return err;
-
- return err;
-}
-
-static void *wl_read_prof(struct wl_priv *wl, s32 item)
+static void *wl_read_prof(struct wl_priv *wl, struct net_device *ndev, s32 item)
{
unsigned long flags;
void *rptr = NULL;
+ struct wl_profile *profile = wl_get_profile_by_netdev(wl, ndev);
- flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
+ if (!profile)
+ return NULL;
+ spin_lock_irqsave(&wl->cfgdrv_lock, flags);
switch (item) {
case WL_PROF_SEC:
- rptr = &wl->profile->sec;
+ rptr = &profile->sec;
break;
case WL_PROF_ACT:
- rptr = &wl->profile->active;
+ rptr = &profile->active;
break;
case WL_PROF_BSSID:
- rptr = &wl->profile->bssid;
+ rptr = profile->bssid;
break;
case WL_PROF_SSID:
- rptr = &wl->profile->ssid;
+ rptr = &profile->ssid;
break;
}
- dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
+ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags);
if (!rptr)
WL_ERR(("invalid item (%d)\n", item));
return rptr;
}
static s32
-wl_update_prof(struct wl_priv *wl, const wl_event_msg_t *e, void *data,
- s32 item)
+wl_update_prof(struct wl_priv *wl, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data, s32 item)
{
s32 err = 0;
struct wlc_ssid *ssid;
unsigned long flags;
+ struct wl_profile *profile = wl_get_profile_by_netdev(wl, ndev);
- flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
+ if (!profile)
+ return WL_INVALID;
+ spin_lock_irqsave(&wl->cfgdrv_lock, flags);
switch (item) {
case WL_PROF_SSID:
ssid = (wlc_ssid_t *) data;
- memset(wl->profile->ssid.SSID, 0,
- sizeof(wl->profile->ssid.SSID));
- memcpy(wl->profile->ssid.SSID, ssid->SSID, ssid->SSID_len);
- wl->profile->ssid.SSID_len = ssid->SSID_len;
+ memset(profile->ssid.SSID, 0,
+ sizeof(profile->ssid.SSID));
+ memcpy(profile->ssid.SSID, ssid->SSID, ssid->SSID_len);
+ profile->ssid.SSID_len = ssid->SSID_len;
break;
case WL_PROF_BSSID:
if (data)
- memcpy(wl->profile->bssid, data, ETHER_ADDR_LEN);
+ memcpy(profile->bssid, data, ETHER_ADDR_LEN);
else
- memset(wl->profile->bssid, 0, ETHER_ADDR_LEN);
+ memset(profile->bssid, 0, ETHER_ADDR_LEN);
break;
case WL_PROF_SEC:
- memcpy(&wl->profile->sec, data, sizeof(wl->profile->sec));
+ memcpy(&profile->sec, data, sizeof(profile->sec));
break;
case WL_PROF_ACT:
- wl->profile->active = *(bool *)data;
+ profile->active = *(bool *)data;
break;
case WL_PROF_BEACONINT:
- wl->profile->beacon_interval = *(u16 *)data;
+ profile->beacon_interval = *(u16 *)data;
break;
case WL_PROF_DTIMPERIOD:
- wl->profile->dtim_period = *(u8 *)data;
+ profile->dtim_period = *(u8 *)data;
break;
default:
WL_ERR(("unsupported item (%d)\n", item));
err = -EOPNOTSUPP;
break;
}
- dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
+ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags);
return err;
}
@@ -6469,7 +7003,7 @@ void wl_cfg80211_dbg_level(u32 level)
static bool wl_is_ibssmode(struct wl_priv *wl, struct net_device *ndev)
{
- return get_mode_by_netdev(wl, ndev) == WL_MODE_IBSS;
+ return wl_get_mode_by_netdev(wl, ndev) == WL_MODE_IBSS;
}
static __used bool wl_is_ibssstarter(struct wl_priv *wl)
@@ -6580,114 +7114,28 @@ static void wl_delay(u32 ms)
}
}
-s32 wl_cfg80211_read_fw(s8 *buf, u32 size)
-{
- const struct firmware *fw_entry;
- struct wl_priv *wl;
-
- wl = wlcfg_drv_priv;
-
- fw_entry = wl->fw->fw_entry;
-
- if (fw_entry->size < wl->fw->ptr + size)
- size = fw_entry->size - wl->fw->ptr;
-
- memcpy(buf, &fw_entry->data[wl->fw->ptr], size);
- wl->fw->ptr += size;
- return size;
-}
-
-void wl_cfg80211_release_fw(void)
-{
- struct wl_priv *wl;
-
- wl = wlcfg_drv_priv;
- release_firmware(wl->fw->fw_entry);
- wl->fw->ptr = 0;
-}
-
-void *wl_cfg80211_request_fw(s8 *file_name)
-{
- struct wl_priv *wl;
- const struct firmware *fw_entry = NULL;
- s32 err = 0;
-
- WL_TRACE(("In\n"));
- WL_DBG(("file name : \"%s\"\n", file_name));
- wl = wlcfg_drv_priv;
-
- if (!test_bit(WL_FW_LOADING_DONE, &wl->fw->status)) {
- err = request_firmware(&wl->fw->fw_entry, file_name,
- &wl_cfg80211_get_sdio_func()->dev);
- if (unlikely(err)) {
- WL_ERR(("Could not download fw (%d)\n", err));
- goto req_fw_out;
- }
- set_bit(WL_FW_LOADING_DONE, &wl->fw->status);
- fw_entry = wl->fw->fw_entry;
- if (fw_entry) {
- WL_DBG(("fw size (%zd), data (%p)\n", fw_entry->size,
- fw_entry->data));
- }
- } else if (!test_bit(WL_NVRAM_LOADING_DONE, &wl->fw->status)) {
- err = request_firmware(&wl->fw->fw_entry, file_name,
- &wl_cfg80211_get_sdio_func()->dev);
- if (unlikely(err)) {
- WL_ERR(("Could not download nvram (%d)\n", err));
- goto req_fw_out;
- }
- set_bit(WL_NVRAM_LOADING_DONE, &wl->fw->status);
- fw_entry = wl->fw->fw_entry;
- if (fw_entry) {
- WL_DBG(("nvram size (%zd), data (%p)\n", fw_entry->size,
- fw_entry->data));
- }
- } else {
- WL_DBG(("Downloading already done. Nothing to do more\n"));
- err = -EPERM;
- }
-
-req_fw_out:
- if (unlikely(err)) {
- return NULL;
- }
- wl->fw->ptr = 0;
- return (void *)fw_entry->data;
-}
-
-s8 *wl_cfg80211_get_fwname(void)
-{
- struct wl_priv *wl;
-
- wl = wlcfg_drv_priv;
- strcpy(wl->fw->fw_name, WL_4329_FW_FILE);
- return wl->fw->fw_name;
-}
-
-s8 *wl_cfg80211_get_nvramname(void)
-{
- struct wl_priv *wl;
-
- wl = wlcfg_drv_priv;
- strcpy(wl->fw->nvram_name, WL_4329_NVRAM_FILE);
- return wl->fw->nvram_name;
-}
-
s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr)
{
- struct wl_priv *wl;
- dhd_pub_t *dhd_pub;
+ struct wl_priv *wl = wlcfg_drv_priv;
struct ether_addr p2pif_addr;
+ struct ether_addr primary_mac;
- wl = wlcfg_drv_priv;
- dhd_pub = (dhd_pub_t *)wl->pub;
- wl_cfgp2p_generate_bss_mac(&dhd_pub->mac, p2pdev_addr, &p2pif_addr);
+ if (!wl->p2p)
+ return -1;
+ if (!p2p_is_on(wl)) {
+ get_primary_mac(wl, &primary_mac);
+ wl_cfgp2p_generate_bss_mac(&primary_mac, p2pdev_addr, &p2pif_addr);
+ } else {
+ memcpy(p2pdev_addr->octet,
+ wl->p2p->dev_addr.octet, ETHER_ADDR_LEN);
+ }
return 0;
}
s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len)
{
struct wl_priv *wl;
+
wl = wlcfg_drv_priv;
return wl_cfgp2p_set_p2p_noa(wl, net, buf, len);
@@ -6721,8 +7169,8 @@ s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len,
if (wl->p2p && wl->p2p->vif_created) {
ndev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION);
bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION);
- } else if (wl_get_drv_status(wl, AP_CREATING) ||
- wl_get_drv_status(wl, AP_CREATED)) {
+ } else if (wl_get_drv_status(wl, AP_CREATING, net) ||
+ wl_get_drv_status(wl, AP_CREATED, net)) {
ndev = net;
bssidx = 0;
}
@@ -6745,69 +7193,6 @@ s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len,
return ret;
}
-static __used void wl_dongle_poweron(struct wl_priv *wl)
-{
- WL_DBG(("Enter \n"));
- dhd_customer_gpio_wlan_ctrl(WLAN_RESET_ON);
-
-#if defined(BCMLXSDMMC)
- sdioh_start(NULL, 0);
-#endif
-#if defined(BCMLXSDMMC)
- sdioh_start(NULL, 1);
-#endif
- wl_cfg80211_resume(wl_to_wiphy(wl));
-}
-
-static __used void wl_dongle_poweroff(struct wl_priv *wl)
-{
- WL_DBG(("Enter \n"));
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)
- wl_cfg80211_suspend(wl_to_wiphy(wl), NULL);
-#else
- wl_cfg80211_suspend(wl_to_wiphy(wl));
-#endif
-
-#if defined(BCMLXSDMMC)
- sdioh_stop(NULL);
-#endif
- /* clean up dtim_skip setting */
- dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF);
-}
-
-static int wl_debugfs_add_netdev_params(struct wl_priv *wl)
-{
- char buf[10+IFNAMSIZ];
- struct dentry *fd;
- s32 err = 0;
-
- WL_TRACE(("In\n"));
- sprintf(buf, "netdev:%s", wl_to_prmry_ndev(wl)->name);
- wl->debugfsdir = debugfs_create_dir(buf, wl_to_wiphy(wl)->debugfsdir);
-
- fd = debugfs_create_u16("beacon_int", S_IRUGO, wl->debugfsdir,
- (u16 *)&wl->profile->beacon_interval);
- if (!fd) {
- err = -ENOMEM;
- goto err_out;
- }
-
- fd = debugfs_create_u8("dtim_period", S_IRUGO, wl->debugfsdir,
- (u8 *)&wl->profile->dtim_period);
- if (!fd) {
- err = -ENOMEM;
- goto err_out;
- }
-
-err_out:
- return err;
-}
-
-static void wl_debugfs_remove_netdev(struct wl_priv *wl)
-{
- WL_DBG(("Enter \n"));
-}
-
static const struct rfkill_ops wl_rfkill_ops = {
.set_block = wl_rfkill_set
};
@@ -6836,7 +7221,7 @@ static int wl_setup_rfkill(struct wl_priv *wl, bool setup)
return -EINVAL;
if (setup) {
wl->rfkill = rfkill_alloc("brcmfmac-wifi",
- &wl_cfg80211_get_sdio_func()->dev,
+ wl_cfg80211_get_parent_dev(),
RFKILL_TYPE_WLAN, &wl_rfkill_ops, (void *)wl);
if (!wl->rfkill) {
@@ -6862,471 +7247,42 @@ err_out:
return err;
}
-#if defined(COEX_DHCP)
-/*
- * get named driver variable to uint register value and return error indication
- * calling example: dev_wlc_intvar_get_reg(dev, "btc_params",66, &reg_value)
- */
-static int
-dev_wlc_intvar_get_reg(struct net_device *dev, char *name,
- uint reg, int *retval)
+struct device *wl_cfg80211_get_parent_dev(void)
{
- union {
- char buf[WLC_IOCTL_SMLEN];
- int val;
- } var;
- int error;
-
- bcm_mkiovar(name, (char *)(&reg), sizeof(reg),
- (char *)(&var), sizeof(var.buf));
- error = wldev_ioctl(dev, WLC_GET_VAR, (char *)(&var), sizeof(var.buf), false);
-
- *retval = dtoh32(var.val);
- return (error);
+ return cfg80211_parent_dev;
}
-static int
-dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len)
+void wl_cfg80211_set_parent_dev(void *dev)
{
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
- char ioctlbuf[1024];
-#else
- static char ioctlbuf[1024];
-#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */
-
- bcm_mkiovar(name, buf, len, ioctlbuf, sizeof(ioctlbuf));
-
- return (wldev_ioctl(dev, WLC_SET_VAR, ioctlbuf, sizeof(ioctlbuf), true));
-}
-/*
-get named driver variable to uint register value and return error indication
-calling example: dev_wlc_intvar_set_reg(dev, "btc_params",66, value)
-*/
-static int
-dev_wlc_intvar_set_reg(struct net_device *dev, char *name, char *addr, char * val)
-{
- char reg_addr[8];
-
- memset(reg_addr, 0, sizeof(reg_addr));
- memcpy((char *)&reg_addr[0], (char *)addr, 4);
- memcpy((char *)&reg_addr[4], (char *)val, 4);
-
- return (dev_wlc_bufvar_set(dev, name, (char *)&reg_addr[0], sizeof(reg_addr)));
+ cfg80211_parent_dev = dev;
}
-static bool btcoex_is_sco_active(struct net_device *dev)
+static void wl_cfg80211_clear_parent_dev(void)
{
- int ioc_res = 0;
- bool res = FALSE;
- int sco_id_cnt = 0;
- int param27;
- int i;
-
- for (i = 0; i < 12; i++) {
-
- ioc_res = dev_wlc_intvar_get_reg(dev, "btc_params", 27, &param27);
-
- WL_TRACE(("%s, sample[%d], btc params: 27:%x\n",
- __FUNCTION__, i, param27));
-
- if (ioc_res < 0) {
- WL_ERR(("%s ioc read btc params error\n", __FUNCTION__));
- break;
- }
-
- if ((param27 & 0x6) == 2) { /* count both sco & esco */
- sco_id_cnt++;
- }
-
- if (sco_id_cnt > 2) {
- WL_TRACE(("%s, sco/esco detected, pkt id_cnt:%d samples:%d\n",
- __FUNCTION__, sco_id_cnt, i));
- res = TRUE;
- break;
- }
-
- msleep(5);
- }
-
- return res;
+ cfg80211_parent_dev = NULL;
}
-#if defined(BT_DHCP_eSCO_FIX)
-/* Enhanced BT COEX settings for eSCO compatibility during DHCP window */
-static int set_btc_esco_params(struct net_device *dev, bool trump_sco)
+static void get_primary_mac(struct wl_priv *wl, struct ether_addr *mac)
{
- static bool saved_status = FALSE;
-
- char buf_reg50va_dhcp_on[8] =
- { 50, 00, 00, 00, 0x22, 0x80, 0x00, 0x00 };
- char buf_reg51va_dhcp_on[8] =
- { 51, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
- char buf_reg64va_dhcp_on[8] =
- { 64, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
- char buf_reg65va_dhcp_on[8] =
- { 65, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
- char buf_reg71va_dhcp_on[8] =
- { 71, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
- uint32 regaddr;
- static uint32 saved_reg50;
- static uint32 saved_reg51;
- static uint32 saved_reg64;
- static uint32 saved_reg65;
- static uint32 saved_reg71;
-
- if (trump_sco) {
- /* this should reduce eSCO agressive retransmit
- * w/o breaking it
- */
-
- /* 1st save current */
- WL_TRACE(("Do new SCO/eSCO coex algo {save &"
- "override}\n"));
- if ((!dev_wlc_intvar_get_reg(dev, "btc_params", 50, &saved_reg50)) &&
- (!dev_wlc_intvar_get_reg(dev, "btc_params", 51, &saved_reg51)) &&
- (!dev_wlc_intvar_get_reg(dev, "btc_params", 64, &saved_reg64)) &&
- (!dev_wlc_intvar_get_reg(dev, "btc_params", 65, &saved_reg65)) &&
- (!dev_wlc_intvar_get_reg(dev, "btc_params", 71, &saved_reg71))) {
- saved_status = TRUE;
- WL_TRACE(("%s saved bt_params[50,51,64,65,71]:"
- "0x%x 0x%x 0x%x 0x%x 0x%x\n",
- __FUNCTION__, saved_reg50, saved_reg51,
- saved_reg64, saved_reg65, saved_reg71));
- } else {
- WL_ERR((":%s: save btc_params failed\n",
- __FUNCTION__));
- saved_status = FALSE;
- return -1;
- }
-
- WL_TRACE(("override with [50,51,64,65,71]:"
- "0x%x 0x%x 0x%x 0x%x 0x%x\n",
- *(u32 *)(buf_reg50va_dhcp_on+4),
- *(u32 *)(buf_reg51va_dhcp_on+4),
- *(u32 *)(buf_reg64va_dhcp_on+4),
- *(u32 *)(buf_reg65va_dhcp_on+4),
- *(u32 *)(buf_reg71va_dhcp_on+4)));
-
- dev_wlc_bufvar_set(dev, "btc_params",
- (char *)&buf_reg50va_dhcp_on[0], 8);
- dev_wlc_bufvar_set(dev, "btc_params",
- (char *)&buf_reg51va_dhcp_on[0], 8);
- dev_wlc_bufvar_set(dev, "btc_params",
- (char *)&buf_reg64va_dhcp_on[0], 8);
- dev_wlc_bufvar_set(dev, "btc_params",
- (char *)&buf_reg65va_dhcp_on[0], 8);
- dev_wlc_bufvar_set(dev, "btc_params",
- (char *)&buf_reg71va_dhcp_on[0], 8);
-
- saved_status = TRUE;
- } else if (saved_status) {
- /* restore previously saved bt params */
- WL_TRACE(("Do new SCO/eSCO coex algo {save &"
- "override}\n"));
-
- regaddr = 50;
- dev_wlc_intvar_set_reg(dev, "btc_params",
- (char *)&regaddr, (char *)&saved_reg50);
- regaddr = 51;
- dev_wlc_intvar_set_reg(dev, "btc_params",
- (char *)&regaddr, (char *)&saved_reg51);
- regaddr = 64;
- dev_wlc_intvar_set_reg(dev, "btc_params",
- (char *)&regaddr, (char *)&saved_reg64);
- regaddr = 65;
- dev_wlc_intvar_set_reg(dev, "btc_params",
- (char *)&regaddr, (char *)&saved_reg65);
- regaddr = 71;
- dev_wlc_intvar_set_reg(dev, "btc_params",
- (char *)&regaddr, (char *)&saved_reg71);
-
- WL_TRACE(("restore bt_params[50,51,64,65,71]:"
- "0x%x 0x%x 0x%x 0x%x 0x%x\n",
- saved_reg50, saved_reg51, saved_reg64,
- saved_reg65, saved_reg71));
-
- saved_status = FALSE;
- } else {
- WL_ERR((":%s att to restore not saved BTCOEX params\n",
- __FUNCTION__));
- return -1;
- }
- return 0;
-}
-#endif /* BT_DHCP_eSCO_FIX */
-
-static void
-wl_cfg80211_bt_setflag(struct net_device *dev, bool set)
-{
-#if defined(BT_DHCP_USE_FLAGS)
- char buf_flag7_dhcp_on[8] = { 7, 00, 00, 00, 0x1, 0x0, 0x00, 0x00 };
- char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
-#endif
-
-#if defined(BT_DHCP_eSCO_FIX)
- /* set = 1, save & turn on 0 - off & restore prev settings */
- set_btc_esco_params(dev, set);
-#endif
-
-#if defined(BT_DHCP_USE_FLAGS)
- WL_TRACE(("WI-FI priority boost via bt flags, set:%d\n", set));
- if (set == TRUE)
- /* Forcing bt_flag7 */
- dev_wlc_bufvar_set(dev, "btc_flags",
- (char *)&buf_flag7_dhcp_on[0],
- sizeof(buf_flag7_dhcp_on));
- else
- /* Restoring default bt flag7 */
- dev_wlc_bufvar_set(dev, "btc_flags",
- (char *)&buf_flag7_default[0],
- sizeof(buf_flag7_default));
-#endif
-}
-
-static void wl_cfg80211_bt_timerfunc(ulong data)
-{
- struct btcoex_info *bt_local = (struct btcoex_info *)data;
- WL_TRACE(("%s\n", __FUNCTION__));
- bt_local->timer_on = 0;
- schedule_work(&bt_local->work);
-}
-
-static void wl_cfg80211_bt_handler(struct work_struct *work)
-{
- struct btcoex_info *btcx_inf;
-
- btcx_inf = container_of(work, struct btcoex_info, work);
-
- if (btcx_inf->timer_on) {
- btcx_inf->timer_on = 0;
- del_timer_sync(&btcx_inf->timer);
- }
-
- switch (btcx_inf->bt_state) {
- case BT_DHCP_START:
- /* DHCP started
- * provide OPPORTUNITY window to get DHCP address
- */
- WL_TRACE(("%s bt_dhcp stm: started \n",
- __FUNCTION__));
- btcx_inf->bt_state = BT_DHCP_OPPR_WIN;
- mod_timer(&btcx_inf->timer,
- jiffies + BT_DHCP_OPPR_WIN_TIME*HZ/1000);
- btcx_inf->timer_on = 1;
- break;
-
- case BT_DHCP_OPPR_WIN:
- if (btcx_inf->dhcp_done) {
- WL_TRACE(("%s DHCP Done before T1 expiration\n",
- __FUNCTION__));
- goto btc_coex_idle;
- }
-
- /* DHCP is not over yet, start lowering BT priority
- * enforce btc_params + flags if necessary
- */
- WL_TRACE(("%s DHCP T1:%d expired\n", __FUNCTION__,
- BT_DHCP_OPPR_WIN_TIME));
- if (btcx_inf->dev)
- wl_cfg80211_bt_setflag(btcx_inf->dev, TRUE);
- btcx_inf->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT;
- mod_timer(&btcx_inf->timer,
- jiffies + BT_DHCP_FLAG_FORCE_TIME*HZ/1000);
- btcx_inf->timer_on = 1;
- break;
-
- case BT_DHCP_FLAG_FORCE_TIMEOUT:
- if (btcx_inf->dhcp_done) {
- WL_TRACE(("%s DHCP Done before T2 expiration\n",
- __FUNCTION__));
- } else {
- /* Noo dhcp during T1+T2, restore BT priority */
- WL_TRACE(("%s DHCP wait interval T2:%d"
- "msec expired\n", __FUNCTION__,
- BT_DHCP_FLAG_FORCE_TIME));
- }
-
- /* Restoring default bt priority */
- if (btcx_inf->dev)
- wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE);
-btc_coex_idle:
- btcx_inf->bt_state = BT_DHCP_IDLE;
- btcx_inf->timer_on = 0;
- break;
-
- default:
- WL_ERR(("%s error g_status=%d !!!\n", __FUNCTION__,
- btcx_inf->bt_state));
- if (btcx_inf->dev)
- wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE);
- btcx_inf->bt_state = BT_DHCP_IDLE;
- btcx_inf->timer_on = 0;
- break;
- }
-
- net_os_wake_unlock(btcx_inf->dev);
+ wldev_iovar_getbuf_bsscfg(wl_to_prmry_ndev(wl), "cur_etheraddr", NULL,
+ 0, wl->ioctl_buf, WLC_IOCTL_MAXLEN, 0, &wl->ioctl_buf_sync);
+ memcpy(mac->octet, wl->ioctl_buf, ETHER_ADDR_LEN);
}
-static int wl_cfg80211_btcoex_init(struct wl_priv *wl)
+int wl_cfg80211_do_driver_init(struct net_device *net)
{
- struct btcoex_info *btco_inf = NULL;
+ struct wl_priv *wl = *(struct wl_priv **)netdev_priv(net);
- btco_inf = kmalloc(sizeof(struct btcoex_info), GFP_KERNEL);
- if (!btco_inf)
- return -ENOMEM;
-
- btco_inf->bt_state = BT_DHCP_IDLE;
- btco_inf->ts_dhcp_start = 0;
- btco_inf->ts_dhcp_ok = 0;
- /* Set up timer for BT */
- btco_inf->timer_ms = 10;
- init_timer(&btco_inf->timer);
- btco_inf->timer.data = (ulong)btco_inf;
- btco_inf->timer.function = wl_cfg80211_bt_timerfunc;
-
- btco_inf->dev = wl->wdev->netdev;
+ if (!wl || !wl->wdev)
+ return -EINVAL;
- INIT_WORK(&btco_inf->work, wl_cfg80211_bt_handler);
+ if (dhd_do_driver_init(wl->wdev->netdev) < 0)
+ return -1;
- wl->btcoex_info = btco_inf;
return 0;
}
-static void
-wl_cfg80211_btcoex_deinit(struct wl_priv *wl)
+void wl_cfg80211_enable_trace(int level)
{
- if (!wl->btcoex_info)
- return;
-
- if (!wl->btcoex_info->timer_on) {
- wl->btcoex_info->timer_on = 0;
- del_timer_sync(&wl->btcoex_info->timer);
- }
-
- cancel_work_sync(&wl->btcoex_info->work);
-
- kfree(wl->btcoex_info);
- wl->btcoex_info = NULL;
-}
-#endif /* COEX_DHCP */
-
-int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command)
-{
- char powermode_val = 0;
- char buf_reg66va_dhcp_on[8] = { 66, 00, 00, 00, 0x10, 0x27, 0x00, 0x00 };
- char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 };
- char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 };
-
- uint32 regaddr;
- static uint32 saved_reg66;
- static uint32 saved_reg41;
- static uint32 saved_reg68;
- static bool saved_status = FALSE;
-
-#ifdef COEX_DHCP
- char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
- struct btcoex_info *btco_inf = wlcfg_drv_priv->btcoex_info;
-#endif /* COEX_DHCP */
-
- /* Figure out powermode 1 or o command */
- strncpy((char *)&powermode_val, command + strlen("BTCOEXMODE") +1, 1);
-
- if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) {
-
- WL_TRACE(("%s: DHCP session starts\n", __FUNCTION__));
-
- /* Retrieve and saved orig regs value */
- if ((saved_status == FALSE) &&
- (!dev_wlc_intvar_get_reg(dev, "btc_params", 66, &saved_reg66)) &&
- (!dev_wlc_intvar_get_reg(dev, "btc_params", 41, &saved_reg41)) &&
- (!dev_wlc_intvar_get_reg(dev, "btc_params", 68, &saved_reg68))) {
- saved_status = TRUE;
- WL_TRACE(("Saved 0x%x 0x%x 0x%x\n",
- saved_reg66, saved_reg41, saved_reg68));
-
- /* Disable PM mode during dhpc session */
-
- /* Disable PM mode during dhpc session */
-#ifdef COEX_DHCP
- /* Start BT timer only for SCO connection */
- if (btcoex_is_sco_active(dev)) {
- /* btc_params 66 */
- dev_wlc_bufvar_set(dev, "btc_params",
- (char *)&buf_reg66va_dhcp_on[0],
- sizeof(buf_reg66va_dhcp_on));
- /* btc_params 41 0x33 */
- dev_wlc_bufvar_set(dev, "btc_params",
- (char *)&buf_reg41va_dhcp_on[0],
- sizeof(buf_reg41va_dhcp_on));
- /* btc_params 68 0x190 */
- dev_wlc_bufvar_set(dev, "btc_params",
- (char *)&buf_reg68va_dhcp_on[0],
- sizeof(buf_reg68va_dhcp_on));
- saved_status = TRUE;
-
- btco_inf->bt_state = BT_DHCP_START;
- btco_inf->timer_on = 1;
- mod_timer(&btco_inf->timer, btco_inf->timer.expires);
- WL_TRACE(("%s enable BT DHCP Timer\n",
- __FUNCTION__));
- }
-#endif /* COEX_DHCP */
- }
- else if (saved_status == TRUE) {
- WL_ERR(("%s was called w/o DHCP OFF. Continue\n", __FUNCTION__));
- }
- }
- else if (strnicmp((char *)&powermode_val, "2", strlen("2")) == 0) {
-
-
- /* Restoring PM mode */
-
-#ifdef COEX_DHCP
- /* Stop any bt timer because DHCP session is done */
- WL_TRACE(("%s disable BT DHCP Timer\n", __FUNCTION__));
- if (btco_inf->timer_on) {
- btco_inf->timer_on = 0;
- del_timer_sync(&btco_inf->timer);
-
- if (btco_inf->bt_state != BT_DHCP_IDLE) {
- /* need to restore original btc flags & extra btc params */
- WL_TRACE(("%s bt->bt_state:%d\n",
- __FUNCTION__, btco_inf->bt_state));
- /* wake up btcoex thread to restore btlags+params */
- schedule_work(&btco_inf->work);
- }
- }
-
- /* Restoring btc_flag paramter anyway */
- if (saved_status == TRUE)
- dev_wlc_bufvar_set(dev, "btc_flags",
- (char *)&buf_flag7_default[0], sizeof(buf_flag7_default));
-#endif /* COEX_DHCP */
-
- /* Restore original values */
- if (saved_status == TRUE) {
- regaddr = 66;
- dev_wlc_intvar_set_reg(dev, "btc_params",
- (char *)&regaddr, (char *)&saved_reg66);
- regaddr = 41;
- dev_wlc_intvar_set_reg(dev, "btc_params",
- (char *)&regaddr, (char *)&saved_reg41);
- regaddr = 68;
- dev_wlc_intvar_set_reg(dev, "btc_params",
- (char *)&regaddr, (char *)&saved_reg68);
-
- WL_TRACE(("restore regs {66,41,68} <- 0x%x 0x%x 0x%x\n",
- saved_reg66, saved_reg41, saved_reg68));
- }
- saved_status = FALSE;
-
- }
- else {
- WL_ERR(("%s Unkwown yet power setting, ignored\n",
- __FUNCTION__));
- }
-
- snprintf(command, 3, "OK");
-
- return (strlen("OK"));
+ wl_dbg_level |= WL_DBG_DBG;
}
diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.h b/drivers/net/wireless/bcmdhd/wl_cfg80211.h
index 262335ef99c2..fba853149c35 100644
--- a/drivers/net/wireless/bcmdhd/wl_cfg80211.h
+++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.h
@@ -68,6 +68,9 @@ do { \
printk args; \
} \
} while (0)
+#ifdef WL_INFO
+#undef WL_INFO
+#endif
#define WL_INFO(args) \
do { \
if (wl_dbg_level & WL_DBG_INFO) { \
@@ -75,6 +78,9 @@ do { \
printk args; \
} \
} while (0)
+#ifdef WL_SCAN
+#undef WL_SCAN
+#endif
#define WL_SCAN(args) \
do { \
if (wl_dbg_level & WL_DBG_SCAN) { \
@@ -82,6 +88,9 @@ do { \
printk args; \
} \
} while (0)
+#ifdef WL_TRACE
+#undef WL_TRACE
+#endif
#define WL_TRACE(args) \
do { \
if (wl_dbg_level & WL_DBG_TRACE) { \
@@ -102,39 +111,32 @@ do { \
#endif /* (WL_DBG_LEVEL > 0) */
-#define WL_SCAN_RETRY_MAX 3 /* used for ibss scan */
-#define WL_NUM_PMKIDS_MAX MAXPMKID /* will be used
- * for 2.6.33 kernel
- * or later
- */
-#define WL_SCAN_BUF_MAX (1024 * 8)
-#define WL_TLV_INFO_MAX 1024
+#define WL_SCAN_RETRY_MAX 3
+#define WL_NUM_PMKIDS_MAX MAXPMKID
+#define WL_SCAN_BUF_MAX (1024 * 8)
+#define WL_TLV_INFO_MAX 1024
#define WL_SCAN_IE_LEN_MAX 2048
-#define WL_BSS_INFO_MAX 2048
-#define WL_ASSOC_INFO_MAX 512 /*
- * needs to grab assoc info from dongle to
- * report it to cfg80211 through "connect"
- * event
- */
+#define WL_BSS_INFO_MAX 2048
+#define WL_ASSOC_INFO_MAX 512
#define WL_IOCTL_LEN_MAX 1024
#define WL_EXTRA_BUF_MAX 2048
-#define WL_ISCAN_BUF_MAX 2048 /*
- * the buf lengh can be WLC_IOCTL_MAXLEN (8K)
- * to reduce iteration
- */
+#define WL_ISCAN_BUF_MAX 2048
#define WL_ISCAN_TIMER_INTERVAL_MS 3000
#define WL_SCAN_ERSULTS_LAST (WL_SCAN_RESULTS_NO_MEM+1)
-#define WL_AP_MAX 256 /* virtually unlimitted as long
- * as kernel memory allows
- */
+#define WL_AP_MAX 256
#define WL_FILE_NAME_MAX 256
-#define WL_DWELL_TIME 200
-#define WL_LONG_DWELL_TIME 1000
-#define VWDEV_CNT 3
+#define WL_DWELL_TIME 200
+#define WL_MED_DWELL_TIME 400
+#define WL_LONG_DWELL_TIME 1000
+#define IFACE_MAX_CNT 2
#define WL_SCAN_TIMER_INTERVAL_MS 8000 /* Scan timeout */
+#define WL_CHANNEL_SYNC_RETRY 3
+#define WL_ACT_FRAME_RETRY 4
-/* dongle status */
+#define WL_INVALID -1
+
+/* driver status */
enum wl_status {
WL_STATUS_READY = 0,
WL_STATUS_SCANNING,
@@ -143,7 +145,8 @@ enum wl_status {
WL_STATUS_CONNECTED,
WL_STATUS_DISCONNECTING,
WL_STATUS_AP_CREATING,
- WL_STATUS_AP_CREATED
+ WL_STATUS_AP_CREATED,
+ WL_STATUS_SENDING_ACT_FRM
};
/* wi-fi mode */
@@ -153,7 +156,7 @@ enum wl_mode {
WL_MODE_AP
};
-/* dongle profile list */
+/* driver profile list */
enum wl_prof_list {
WL_PROF_MODE,
WL_PROF_SSID,
@@ -166,7 +169,7 @@ enum wl_prof_list {
WL_PROF_DTIMPERIOD
};
-/* dongle iscan state */
+/* driver iscan state */
enum wl_iscan_state {
WL_ISCAN_STATE_IDLE,
WL_ISCAN_STATE_SCANING
@@ -196,12 +199,8 @@ struct beacon_proberesp {
u8 variable[0];
} __attribute__ ((packed));
-/* dongle configuration */
+/* driver configuration */
struct wl_conf {
- struct net_mode {
- struct net_device *ndev;
- s32 type;
- } mode [VWDEV_CNT + 1]; /* adhoc , infrastructure or ap */
u32 frag_threshold;
u32 rts_threshold;
u32 retry_short;
@@ -259,22 +258,30 @@ struct wl_ibss {
u8 channel;
};
-/* dongle profile */
+/* wl driver profile */
struct wl_profile {
u32 mode;
+ s32 band;
struct wlc_ssid ssid;
+ struct wl_security sec;
+ struct wl_ibss ibss;
u8 bssid[ETHER_ADDR_LEN];
u16 beacon_interval;
u8 dtim_period;
- struct wl_security sec;
- struct wl_ibss ibss;
- s32 band;
bool active;
};
+struct net_info {
+ struct net_device *ndev;
+ struct wireless_dev *wdev;
+ struct wl_profile profile;
+ s32 mode;
+ unsigned long sme_state;
+ struct list_head list; /* list of all net_info structure */
+};
typedef s32(*ISCAN_HANDLER) (struct wl_priv *wl);
-/* dongle iscan controller */
+/* iscan controller */
struct wl_iscan_ctrl {
struct net_device *dev;
struct timer_list timer;
@@ -323,9 +330,10 @@ struct wl_pmk_list {
#define ESCAN_BUF_SIZE (64 * 1024)
struct escan_info {
- u32 escan_state;
- u8 escan_buf[ESCAN_BUF_SIZE];
- struct wiphy *wiphy;
+ u32 escan_state;
+ u8 escan_buf[ESCAN_BUF_SIZE];
+ struct wiphy *wiphy;
+ struct net_device *ndev;
};
struct ap_info {
@@ -341,14 +349,14 @@ struct ap_info {
};
struct btcoex_info {
struct timer_list timer;
- uint32 timer_ms;
- uint32 timer_on;
- uint32 ts_dhcp_start; /* ms ts ecord time stats */
- uint32 ts_dhcp_ok; /* ms ts ecord time stats */
- bool dhcp_done; /* flag, indicates that host done with
- * dhcp before t1/t2 expiration
- */
- int bt_state;
+ u32 timer_ms;
+ u32 timer_on;
+ u32 ts_dhcp_start; /* ms ts ecord time stats */
+ u32 ts_dhcp_ok; /* ms ts ecord time stats */
+ bool dhcp_done; /* flag, indicates that host done with
+ * dhcp before t1/t2 expiration
+ */
+ s32 bt_state;
struct work_struct work;
struct net_device *dev;
};
@@ -360,40 +368,50 @@ struct sta_info {
u32 probe_req_ie_len;
u32 assoc_req_ie_len;
};
-/* dongle private data of cfg80211 interface */
+
+struct afx_hdl {
+ wl_af_params_t *pending_tx_act_frm;
+ struct ether_addr pending_tx_dst_addr;
+ struct net_device *dev;
+ struct work_struct work;
+ u32 bssidx;
+ u32 retry;
+ s32 peer_chan;
+ bool ack_recv;
+};
+
+/* private data of cfg80211 interface */
struct wl_priv {
struct wireless_dev *wdev; /* representing wl cfg80211 device */
- struct wireless_dev *vwdev[VWDEV_CNT];
- struct wl_conf *conf; /* dongle configuration */
+
+ struct wireless_dev *p2p_wdev; /* representing wl cfg80211 device for P2P */
+ struct net_device *p2p_net; /* reference to p2p0 interface */
+
+ struct wl_conf *conf;
struct cfg80211_scan_request *scan_request; /* scan request object */
EVENT_HANDLER evt_handler[WLC_E_LAST];
struct list_head eq_list; /* used for event queue */
+ struct list_head net_list; /* used for struct net_info */
spinlock_t eq_lock; /* for event queue synchronization */
- struct mutex usr_sync; /* maily for dongle up/down synchronization */
+ spinlock_t cfgdrv_lock; /* to protect scan status (and others if needed) */
+ struct completion act_frm_scan;
+ struct mutex usr_sync; /* maily for up/down synchronization */
struct wl_scan_results *bss_list;
struct wl_scan_results *scan_results;
/* scan request object for internal purpose */
struct wl_scan_req *scan_req_int;
-
- /* bss information for cfg80211 layer */
- struct wl_cfg80211_bss_info *bss_info;
/* information element object for internal purpose */
struct wl_ie ie;
-
- /* for synchronization of main event thread */
- struct wl_profile *profile; /* holding dongle profile */
struct wl_iscan_ctrl *iscan; /* iscan controller */
/* association information container */
struct wl_connect_info conn_info;
- /* control firwmare and nvram paramter downloading */
- struct wl_fw_ctrl *fw;
struct wl_pmk_list *pmk_list; /* wpa2 pmk list */
tsk_ctl_t event_tsk; /* task of main event handler thread */
- unsigned long status; /* current dongle status */
void *pub;
+ u32 iface_cnt;
u32 channel; /* current channel */
bool iscan_on; /* iscan on/off switch */
bool iscan_kickstart; /* indicate iscan already started */
@@ -403,12 +421,12 @@ struct wl_priv {
bool ibss_starter; /* indicates this sta is ibss starter */
bool link_up; /* link/connection up flag */
- /* indicate whether dongle to support power save mode */
+ /* indicate whether chip to support power save mode */
bool pwr_save;
- bool dongle_up; /* indicate whether dongle up or not */
- bool roam_on; /* on/off switch for dongle self-roaming */
+ bool roam_on; /* on/off switch for self-roaming */
bool scan_tried; /* indicates if first scan attempted */
- u8 *ioctl_buf; /* ioctl buffer */
+ u8 *ioctl_buf; /* ioctl buffer */
+ struct mutex ioctl_buf_sync;
u8 *escan_ioctl_buf;
u8 *extra_buf; /* maily to grab assoc information */
struct dentry *debugfsdir;
@@ -416,131 +434,224 @@ struct wl_priv {
bool rf_blocked;
struct ieee80211_channel remain_on_chan;
enum nl80211_channel_type remain_on_chan_type;
- u64 cache_cookie;
- wait_queue_head_t dongle_event_wait;
+ u64 send_action_id;
+ u64 last_roc_id;
+ wait_queue_head_t netif_change_event;
+ struct afx_hdl *afx_hdl;
struct ap_info *ap_info;
struct sta_info *sta_info;
struct p2p_info *p2p;
bool p2p_supported;
struct btcoex_info *btcoex_info;
struct timer_list scan_timeout; /* Timer for catch scan event timeout */
+#ifdef WL_SCHED_SCAN
+ struct cfg80211_sched_scan_request *sched_scan_req; /* scheduled scan req */
+#endif /* WL_SCHED_SCAN */
+ bool sched_scan_running; /* scheduled scan req status */
+ u16 hostapd_chan; /* remember chan requested by framework for hostapd */
+ u16 deauth_reason; /* Place holder to save deauth/disassoc reasons */
};
-#define wl_to_wiphy(w) (w->wdev->wiphy)
-#define wl_to_prmry_ndev(w) (w->wdev->netdev)
-#define ndev_to_wl(n) (wdev_to_wl(n->ieee80211_ptr))
-#define wl_to_sr(w) (w->scan_req_int)
-#define wl_to_ie(w) (&w->ie)
-#define iscan_to_wl(i) ((struct wl_priv *)(i->data))
-#define wl_to_iscan(w) (w->iscan)
-#define wl_to_conn(w) (&w->conn_info)
-#define wiphy_from_scan(w) (w->escan_info.wiphy)
-#define wl_get_drv_status(wl, stat) (test_bit(WL_STATUS_ ## stat, &(wl)->status))
-#define wl_set_drv_status(wl, stat) (set_bit(WL_STATUS_ ## stat, &(wl)->status))
-#define wl_clr_drv_status(wl, stat) (clear_bit(WL_STATUS_ ## stat, &(wl)->status))
-#define wl_chg_drv_status(wl, stat) (change_bit(WL_STATUS_ ## stat, &(wl)->status))
-
static inline struct wl_bss_info *next_bss(struct wl_scan_results *list, struct wl_bss_info *bss)
{
return bss = bss ?
(struct wl_bss_info *)((uintptr) bss + dtoh32(bss->length)) : list->bss_info;
}
-static inline s32 alloc_idx_vwdev(struct wl_priv *wl)
+
+static inline s32
+wl_alloc_netinfo(struct wl_priv *wl, struct net_device *ndev,
+ struct wireless_dev * wdev, s32 mode)
{
- s32 i = 0;
- for (i = 0; i < VWDEV_CNT; i++) {
- if (wl->vwdev[i] == NULL)
- return i;
+ struct net_info *_net_info;
+ s32 err = 0;
+ if (wl->iface_cnt == IFACE_MAX_CNT)
+ return -ENOMEM;
+ _net_info = kzalloc(sizeof(struct net_info), GFP_KERNEL);
+ if (!_net_info)
+ err = -ENOMEM;
+ else {
+ _net_info->mode = mode;
+ _net_info->ndev = ndev;
+ _net_info->wdev = wdev;
+ wl->iface_cnt++;
+ list_add(&_net_info->list, &wl->net_list);
}
- return -1;
+ return err;
}
-static inline s32 get_idx_vwdev_by_netdev(struct wl_priv *wl, struct net_device *ndev)
+static inline void
+wl_dealloc_netinfo(struct wl_priv *wl, struct net_device *ndev)
{
- s32 i = 0;
- for (i = 0; i < VWDEV_CNT; i++) {
- if ((wl->vwdev[i] != NULL) && (wl->vwdev[i]->netdev == ndev))
- return i;
+ struct net_info *_net_info, *next;
+
+ list_for_each_entry_safe(_net_info, next, &wl->net_list, list) {
+ if (ndev && (_net_info->ndev == ndev)) {
+ list_del(&_net_info->list);
+ wl->iface_cnt--;
+ if (_net_info->wdev) {
+ kfree(_net_info->wdev);
+ ndev->ieee80211_ptr = NULL;
+ }
+ kfree(_net_info);
+ }
}
- return -1;
}
-static inline s32 get_mode_by_netdev(struct wl_priv *wl, struct net_device *ndev)
+static inline void
+wl_delete_all_netinfo(struct wl_priv *wl)
{
- s32 i = 0;
- for (i = 0; i <= VWDEV_CNT; i++) {
- if (wl->conf->mode[i].ndev != NULL && (wl->conf->mode[i].ndev == ndev))
- return wl->conf->mode[i].type;
+ struct net_info *_net_info, *next;
+
+ list_for_each_entry_safe(_net_info, next, &wl->net_list, list) {
+ list_del(&_net_info->list);
+ if (_net_info->wdev)
+ kfree(_net_info->wdev);
+ kfree(_net_info);
}
- return -1;
+ wl->iface_cnt = 0;
}
-static inline void set_mode_by_netdev(struct wl_priv *wl, struct net_device *ndev, s32 type)
+
+static inline bool
+wl_get_status_all(struct wl_priv *wl, s32 status)
+
{
- s32 i = 0;
- for (i = 0; i <= VWDEV_CNT; i++) {
- if (type == -1) {
- /* free the info of netdev */
- if (wl->conf->mode[i].ndev == ndev) {
- wl->conf->mode[i].ndev = NULL;
- wl->conf->mode[i].type = -1;
- break;
- }
+ struct net_info *_net_info, *next;
+ u32 cnt = 0;
+ list_for_each_entry_safe(_net_info, next, &wl->net_list, list) {
+ if (_net_info->ndev &&
+ test_bit(status, &_net_info->sme_state))
+ cnt++;
+ }
+ return cnt? true: false;
+}
- } else {
- if ((wl->conf->mode[i].ndev != NULL)&&
- (wl->conf->mode[i].ndev == ndev)) {
- /* update type of ndev */
- wl->conf->mode[i].type = type;
- break;
- }
- else if ((wl->conf->mode[i].ndev == NULL)&&
- (wl->conf->mode[i].type == -1)) {
- wl->conf->mode[i].ndev = ndev;
- wl->conf->mode[i].type = type;
- break;
+static inline void
+wl_set_status_by_netdev(struct wl_priv *wl, s32 status,
+ struct net_device *ndev, u32 op)
+{
+
+ struct net_info *_net_info, *next;
+
+ list_for_each_entry_safe(_net_info, next, &wl->net_list, list) {
+ if (ndev && (_net_info->ndev == ndev)) {
+ switch (op) {
+ case 1:
+ set_bit(status, &_net_info->sme_state);
+ break;
+ case 2:
+ clear_bit(status, &_net_info->sme_state);
+ break;
+ case 4:
+ change_bit(status, &_net_info->sme_state);
+ break;
}
}
+
+ }
+}
+
+static inline u32
+wl_get_status_by_netdev(struct wl_priv *wl, s32 status,
+ struct net_device *ndev)
+{
+ struct net_info *_net_info, *next;
+
+ list_for_each_entry_safe(_net_info, next, &wl->net_list, list) {
+ if (ndev && (_net_info->ndev == ndev))
+ return test_bit(status, &_net_info->sme_state);
+ }
+ return 0;
+}
+
+static inline s32
+wl_get_mode_by_netdev(struct wl_priv *wl, struct net_device *ndev)
+{
+ struct net_info *_net_info, *next;
+
+ list_for_each_entry_safe(_net_info, next, &wl->net_list, list) {
+ if (ndev && (_net_info->ndev == ndev))
+ return _net_info->mode;
+ }
+ return -1;
+}
+
+static inline void
+wl_set_mode_by_netdev(struct wl_priv *wl, struct net_device *ndev,
+ s32 mode)
+{
+ struct net_info *_net_info, *next;
+
+ list_for_each_entry_safe(_net_info, next, &wl->net_list, list) {
+ if (ndev && (_net_info->ndev == ndev))
+ _net_info->mode = mode;
+ }
+}
+
+static inline struct wl_profile *
+wl_get_profile_by_netdev(struct wl_priv *wl, struct net_device *ndev)
+{
+ struct net_info *_net_info, *next;
+
+ list_for_each_entry_safe(_net_info, next, &wl->net_list, list) {
+ if (ndev && (_net_info->ndev == ndev))
+ return &_net_info->profile;
}
+ return NULL;
}
-#define free_vwdev_by_index(wl, __i) do { \
- if (wl->vwdev[__i] != NULL) \
- kfree(wl->vwdev[__i]); \
- wl->vwdev[__i] = NULL; \
- } while (0)
+#define wl_to_wiphy(w) (w->wdev->wiphy)
+#define wl_to_prmry_ndev(w) (w->wdev->netdev)
+#define ndev_to_wl(n) (wdev_to_wl(n->ieee80211_ptr))
+#define wl_to_sr(w) (w->scan_req_int)
+#define wl_to_ie(w) (&w->ie)
+#define iscan_to_wl(i) ((struct wl_priv *)(i->data))
+#define wl_to_iscan(w) (w->iscan)
+#define wl_to_conn(w) (&w->conn_info)
+#define wiphy_from_scan(w) (w->escan_info.wiphy)
+#define wl_get_drv_status_all(wl, stat) \
+ (wl_get_status_all(wl, WL_STATUS_ ## stat))
+#define wl_get_drv_status(wl, stat, ndev) \
+ (wl_get_status_by_netdev(wl, WL_STATUS_ ## stat, ndev))
+#define wl_set_drv_status(wl, stat, ndev) \
+ (wl_set_status_by_netdev(wl, WL_STATUS_ ## stat, ndev, 1))
+#define wl_clr_drv_status(wl, stat, ndev) \
+ (wl_set_status_by_netdev(wl, WL_STATUS_ ## stat, ndev, 2))
+#define wl_chg_drv_status(wl, stat, ndev) \
+ (wl_set_status_by_netdev(wl, WL_STATUS_ ## stat, ndev, 4))
#define for_each_bss(list, bss, __i) \
for (__i = 0; __i < list->count && __i < WL_AP_MAX; __i++, bss = next_bss(list, bss))
+#define for_each_ndev(wl, iter, next) \
+ list_for_each_entry_safe(iter, next, &wl->net_list, list)
+
+
/* In case of WPS from wpa_supplicant, pairwise siute and group suite is 0.
* In addtion to that, wpa_version is WPA_VERSION_1
*/
#define is_wps_conn(_sme) \
- ((_sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) && \
+ ((wl_cfgp2p_find_wpsie((u8 *)_sme->ie, _sme->ie_len) != NULL) && \
(!_sme->crypto.n_ciphers_pairwise) && \
(!_sme->crypto.cipher_group))
extern s32 wl_cfg80211_attach(struct net_device *ndev, void *data);
extern s32 wl_cfg80211_attach_post(struct net_device *ndev);
-extern void wl_cfg80211_detach(void);
-/* event handler from dongle */
+extern void wl_cfg80211_detach(void *para);
+
extern void wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t *e,
void *data);
-extern void wl_cfg80211_set_sdio_func(void *func); /* set sdio function info */
-extern struct sdio_func *wl_cfg80211_get_sdio_func(void); /* set sdio function info */
-extern s32 wl_cfg80211_up(void); /* dongle up */
-extern s32 wl_cfg80211_down(void); /* dongle down */
-extern s32 wl_cfg80211_notify_ifadd(struct net_device *net, s32 idx, s32 bssidx,
-int (*_net_attach)(dhd_pub_t *dhdp, int ifidx));
-extern s32 wl_cfg80211_notify_ifdel(struct net_device *ndev);
+void wl_cfg80211_set_parent_dev(void *dev);
+struct device *wl_cfg80211_get_parent_dev(void);
+
+extern s32 wl_cfg80211_up(void *para);
+extern s32 wl_cfg80211_down(void *para);
+extern s32 wl_cfg80211_notify_ifadd(struct net_device *ndev, s32 idx, s32 bssidx,
+ void* _net_attach);
+extern s32 wl_cfg80211_ifdel_ops(struct net_device *net);
+extern s32 wl_cfg80211_notify_ifdel(void);
extern s32 wl_cfg80211_is_progress_ifadd(void);
extern s32 wl_cfg80211_is_progress_ifchange(void);
extern s32 wl_cfg80211_is_progress_ifadd(void);
extern s32 wl_cfg80211_notify_ifchange(void);
extern void wl_cfg80211_dbg_level(u32 level);
-extern void *wl_cfg80211_request_fw(s8 *file_name);
-extern s32 wl_cfg80211_read_fw(s8 *buf, u32 size);
-extern void wl_cfg80211_release_fw(void);
-extern s8 *wl_cfg80211_get_fwname(void);
-extern s8 *wl_cfg80211_get_nvramname(void);
extern s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr);
extern s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len);
extern s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len);
@@ -548,11 +659,8 @@ extern s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len
enum wl_management_type type);
extern s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len);
extern int wl_cfg80211_hang(struct net_device *dev, u16 reason);
-
-/* do scan abort */
-extern s32
-wl_cfg80211_scan_abort(struct wl_priv *wl, struct net_device *ndev);
-
-extern s32
-wl_cfg80211_if_is_group_owner(void);
+extern s32 wl_mode_to_nl80211_iftype(s32 mode);
+int wl_cfg80211_do_driver_init(struct net_device *net);
+void wl_cfg80211_enable_trace(int level);
+extern s32 wl_cfg80211_if_is_group_owner(void);
#endif /* _wl_cfg80211_h_ */
diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c
index 4ee6557e17dd..a34c4ad17c25 100644
--- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c
+++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c
@@ -30,6 +30,7 @@
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/timer.h>
@@ -39,26 +40,199 @@
#include <bcmutils.h>
#include <bcmendian.h>
#include <proto/ethernet.h>
-#include <dngl_stats.h>
-#include <dhd.h>
-#include <dhdioctl.h>
-#include <wlioctl.h>
#include <wl_cfg80211.h>
#include <wl_cfgp2p.h>
#include <wldev_common.h>
+#include <wl_android.h>
-
-static s8 ioctlbuf[WLC_IOCTL_MAXLEN];
static s8 scanparambuf[WLC_IOCTL_SMLEN];
-static s8 *smbuf = ioctlbuf;
static bool
wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type);
static s32
-wl_cfgp2p_vndr_ie(struct net_device *ndev, s32 bssidx, s32 pktflag,
+wl_cfgp2p_vndr_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx, s32 pktflag,
s8 *oui, s32 ie_id, s8 *data, s32 data_len, s32 delete);
+
+static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev);
+static int wl_cfgp2p_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd);
+static int wl_cfgp2p_if_open(struct net_device *net);
+static int wl_cfgp2p_if_stop(struct net_device *net);
+
+static const struct net_device_ops wl_cfgp2p_if_ops = {
+ .ndo_open = wl_cfgp2p_if_open,
+ .ndo_stop = wl_cfgp2p_if_stop,
+ .ndo_do_ioctl = wl_cfgp2p_do_ioctl,
+ .ndo_start_xmit = wl_cfgp2p_start_xmit,
+};
+
+bool wl_cfgp2p_is_pub_action(void *frame, u32 frame_len)
+{
+ wifi_p2p_pub_act_frame_t *pact_frm;
+
+ if (frame == NULL)
+ return false;
+ pact_frm = (wifi_p2p_pub_act_frame_t *)frame;
+ if (frame_len < sizeof(wifi_p2p_pub_act_frame_t) -1)
+ return false;
+
+ if (pact_frm->category == P2P_PUB_AF_CATEGORY &&
+ pact_frm->action == P2P_PUB_AF_ACTION &&
+ pact_frm->oui_type == P2P_VER &&
+ memcmp(pact_frm->oui, P2P_OUI, sizeof(pact_frm->oui)) == 0) {
+ return true;
+ }
+
+ return false;
+}
+
+bool wl_cfgp2p_is_p2p_action(void *frame, u32 frame_len)
+{
+ wifi_p2p_action_frame_t *act_frm;
+
+ if (frame == NULL)
+ return false;
+ act_frm = (wifi_p2p_action_frame_t *)frame;
+ if (frame_len < sizeof(wifi_p2p_action_frame_t) -1)
+ return false;
+
+ if (act_frm->category == P2P_AF_CATEGORY &&
+ act_frm->type == P2P_VER &&
+ memcmp(act_frm->OUI, P2P_OUI, DOT11_OUI_LEN) == 0) {
+ return true;
+ }
+
+ return false;
+}
+
+bool wl_cfgp2p_is_gas_action(void *frame, u32 frame_len)
+{
+
+ wifi_p2psd_gas_pub_act_frame_t *sd_act_frm;
+
+ if (frame == NULL)
+ return false;
+
+ sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)frame;
+ if (frame_len < sizeof(wifi_p2psd_gas_pub_act_frame_t) - 1)
+ return false;
+ if (sd_act_frm->category != P2PSD_ACTION_CATEGORY)
+ return false;
+
+ if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ ||
+ sd_act_frm->action == P2PSD_ACTION_ID_GAS_IRESP ||
+ sd_act_frm->action == P2PSD_ACTION_ID_GAS_CREQ ||
+ sd_act_frm->action == P2PSD_ACTION_ID_GAS_CRESP)
+ return true;
+ else
+ return false;
+
+}
+
+void wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len)
+{
+ wifi_p2p_pub_act_frame_t *pact_frm;
+ wifi_p2p_action_frame_t *act_frm;
+ wifi_p2psd_gas_pub_act_frame_t *sd_act_frm;
+ if (!frame || frame_len <= 2)
+ return;
+
+ if (wl_cfgp2p_is_pub_action(frame, frame_len)) {
+ pact_frm = (wifi_p2p_pub_act_frame_t *)frame;
+ switch (pact_frm->subtype) {
+ case P2P_PAF_GON_REQ:
+ CFGP2P_DBG(("%s P2P Group Owner Negotiation Req Frame\n",
+ (tx)? "TX": "RX"));
+ break;
+ case P2P_PAF_GON_RSP:
+ CFGP2P_DBG(("%s P2P Group Owner Negotiation Rsp Frame\n",
+ (tx)? "TX": "RX"));
+ break;
+ case P2P_PAF_GON_CONF:
+ CFGP2P_DBG(("%s P2P Group Owner Negotiation Confirm Frame\n",
+ (tx)? "TX": "RX"));
+ break;
+ case P2P_PAF_INVITE_REQ:
+ CFGP2P_DBG(("%s P2P Invitation Request Frame\n",
+ (tx)? "TX": "RX"));
+ break;
+ case P2P_PAF_INVITE_RSP:
+ CFGP2P_DBG(("%s P2P Invitation Response Frame\n",
+ (tx)? "TX": "RX"));
+ break;
+ case P2P_PAF_DEVDIS_REQ:
+ CFGP2P_DBG(("%s P2P Device Discoverability Request Frame\n",
+ (tx)? "TX": "RX"));
+ break;
+ case P2P_PAF_DEVDIS_RSP:
+ CFGP2P_DBG(("%s P2P Device Discoverability Response Frame\n",
+ (tx)? "TX": "RX"));
+ break;
+ case P2P_PAF_PROVDIS_REQ:
+ CFGP2P_DBG(("%s P2P Provision Discovery Request Frame\n",
+ (tx)? "TX": "RX"));
+ break;
+ case P2P_PAF_PROVDIS_RSP:
+ CFGP2P_DBG(("%s P2P Provision Discovery Response Frame\n",
+ (tx)? "TX": "RX"));
+ break;
+ default:
+ CFGP2P_DBG(("%s Unknown P2P Public Action Frame\n",
+ (tx)? "TX": "RX"));
+
+ }
+
+ } else if (wl_cfgp2p_is_p2p_action(frame, frame_len)) {
+ act_frm = (wifi_p2p_action_frame_t *)frame;
+ switch (act_frm->subtype) {
+ case P2P_AF_NOTICE_OF_ABSENCE:
+ CFGP2P_DBG(("%s P2P Notice of Absence Frame\n",
+ (tx)? "TX": "RX"));
+ break;
+ case P2P_AF_PRESENCE_REQ:
+ CFGP2P_DBG(("%s P2P Presence Request Frame\n",
+ (tx)? "TX": "RX"));
+ break;
+ case P2P_AF_PRESENCE_RSP:
+ CFGP2P_DBG(("%s P2P Presence Response Frame\n",
+ (tx)? "TX": "RX"));
+ break;
+ case P2P_AF_GO_DISC_REQ:
+ CFGP2P_DBG(("%s P2P Discoverability Request Frame\n",
+ (tx)? "TX": "RX"));
+ break;
+ default:
+ CFGP2P_DBG(("%s Unknown P2P Action Frame\n",
+ (tx)? "TX": "RX"));
+ }
+
+ } else if (wl_cfgp2p_is_gas_action(frame, frame_len)) {
+ sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)frame;
+ switch (sd_act_frm->action) {
+ case P2PSD_ACTION_ID_GAS_IREQ:
+ CFGP2P_DBG(("%s P2P GAS Initial Request\n",
+ (tx)? "TX" : "RX"));
+ break;
+ case P2PSD_ACTION_ID_GAS_IRESP:
+ CFGP2P_DBG(("%s P2P GAS Initial Response\n",
+ (tx)? "TX" : "RX"));
+ break;
+ case P2PSD_ACTION_ID_GAS_CREQ:
+ CFGP2P_DBG(("%s P2P GAS Comback Request\n",
+ (tx)? "TX" : "RX"));
+ break;
+ case P2PSD_ACTION_ID_GAS_CRESP:
+ CFGP2P_DBG(("%s P2P GAS Comback Response\n",
+ (tx)? "TX" : "RX"));
+ break;
+ default:
+ CFGP2P_DBG(("%s Unknown P2P GAS Frame\n",
+ (tx)? "TX" : "RX"));
+ }
+ }
+}
+
/*
* Initialize variables related to P2P
*
@@ -99,7 +273,6 @@ wl_cfgp2p_init_priv(struct wl_priv *wl)
wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = 0;
wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION) = NULL;
wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION) = 0;
- spin_lock_init(&wl->p2p->timer_lock);
return BCME_OK;
}
@@ -110,6 +283,8 @@ wl_cfgp2p_init_priv(struct wl_priv *wl)
void
wl_cfgp2p_deinit_priv(struct wl_priv *wl)
{
+ CFGP2P_DBG(("In\n"));
+
if (wl->p2p) {
kfree(wl->p2p);
wl->p2p = NULL;
@@ -142,9 +317,9 @@ wl_cfgp2p_set_firm_p2p(struct wl_priv *wl)
* firmware for P2P device address
*/
ret = wldev_iovar_setbuf_bsscfg(ndev, "p2p_da_override", &null_eth_addr,
- sizeof(null_eth_addr), ioctlbuf, sizeof(ioctlbuf), 0);
+ sizeof(null_eth_addr), wl->ioctl_buf, WLC_IOCTL_MAXLEN, 0, &wl->ioctl_buf_sync);
if (ret && ret != BCME_UNSUPPORTED) {
- CFGP2P_ERR(("failed to update device address\n"));
+ CFGP2P_ERR(("failed to update device address ret %d\n", ret));
}
return ret;
}
@@ -168,14 +343,14 @@ wl_cfgp2p_ifadd(struct wl_priv *wl, struct ether_addr *mac, u8 if_type,
ifreq.chspec = chspec;
memcpy(ifreq.addr.octet, mac->octet, sizeof(ifreq.addr.octet));
- CFGP2P_INFO(("---wl p2p_ifadd %02x:%02x:%02x:%02x:%02x:%02x %s %u\n",
+ CFGP2P_DBG(("---wl p2p_ifadd %02x:%02x:%02x:%02x:%02x:%02x %s %u\n",
ifreq.addr.octet[0], ifreq.addr.octet[1], ifreq.addr.octet[2],
ifreq.addr.octet[3], ifreq.addr.octet[4], ifreq.addr.octet[5],
(if_type == WL_P2P_IF_GO) ? "go" : "client",
(chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT));
err = wldev_iovar_setbuf(ndev, "p2p_ifadd", &ifreq, sizeof(ifreq),
- ioctlbuf, sizeof(ioctlbuf));
+ wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync);
return err;
}
@@ -194,7 +369,7 @@ wl_cfgp2p_ifdel(struct wl_priv *wl, struct ether_addr *mac)
netdev->ifindex, mac->octet[0], mac->octet[1], mac->octet[2],
mac->octet[3], mac->octet[4], mac->octet[5]));
ret = wldev_iovar_setbuf(netdev, "p2p_ifdel", mac, sizeof(*mac),
- ioctlbuf, sizeof(ioctlbuf));
+ wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync);
if (unlikely(ret < 0)) {
printk("'wl p2p_ifdel' error %d\n", ret);
}
@@ -225,7 +400,7 @@ wl_cfgp2p_ifchange(struct wl_priv *wl, struct ether_addr *mac, u8 if_type,
(chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT));
err = wldev_iovar_setbuf(netdev, "p2p_ifupd", &ifreq, sizeof(ifreq),
- ioctlbuf, sizeof(ioctlbuf));
+ wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync);
if (unlikely(err < 0)) {
printk("'wl p2p_ifupd' error %d\n", err);
@@ -251,8 +426,8 @@ wl_cfgp2p_ifidx(struct wl_priv *wl, struct ether_addr *mac, s32 *index)
mac->octet[0], mac->octet[1], mac->octet[2],
mac->octet[3], mac->octet[4], mac->octet[5]));
- ret = wldev_iovar_getbuf_bsscfg(dev, "p2p_if", mac, sizeof(*mac),
- getbuf, sizeof(getbuf), wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_PRIMARY));
+ ret = wldev_iovar_getbuf_bsscfg(dev, "p2p_if", mac, sizeof(*mac), getbuf,
+ sizeof(getbuf), wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_PRIMARY), NULL);
if (ret == 0) {
memcpy(index, getbuf, sizeof(index));
@@ -262,7 +437,7 @@ wl_cfgp2p_ifidx(struct wl_priv *wl, struct ether_addr *mac, s32 *index)
return ret;
}
-s32
+static s32
wl_cfgp2p_set_discovery(struct wl_priv *wl, s32 on)
{
s32 ret = BCME_OK;
@@ -311,13 +486,14 @@ wl_cfgp2p_set_p2p_mode(struct wl_priv *wl, u8 mode, u32 channel, u16 listen_ms,
discovery_mode.chspec = CH20MHZ_CHSPEC(channel);
discovery_mode.dwell = listen_ms;
ret = wldev_iovar_setbuf_bsscfg(dev, "p2p_state", &discovery_mode,
- sizeof(discovery_mode), ioctlbuf, sizeof(ioctlbuf), bssidx);
+ sizeof(discovery_mode), wl->ioctl_buf, WLC_IOCTL_MAXLEN,
+ bssidx, &wl->ioctl_buf_sync);
return ret;
}
/* Get the index of the P2P Discovery BSS */
-s32
+static s32
wl_cfgp2p_get_disc_idx(struct wl_priv *wl, s32 *index)
{
s32 ret;
@@ -364,7 +540,7 @@ wl_cfgp2p_init_discovery(struct wl_priv *wl)
/* Set the initial discovery state to SCAN */
ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0,
- wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE));
+ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE));
if (unlikely(ret != 0)) {
CFGP2P_ERR(("unable to set WL_P2P_DISC_ST_SCAN\n"));
@@ -381,7 +557,7 @@ wl_cfgp2p_init_discovery(struct wl_priv *wl)
* @wl : wl_private data
* Returns 0 if succes
*/
-s32
+static s32
wl_cfgp2p_deinit_discovery(struct wl_priv *wl)
{
s32 ret = BCME_OK;
@@ -419,7 +595,8 @@ wl_cfgp2p_deinit_discovery(struct wl_priv *wl)
* Returns 0 if success.
*/
s32
-wl_cfgp2p_enable_discovery(struct wl_priv *wl, struct net_device *dev, const u8 *ie, u32 ie_len)
+wl_cfgp2p_enable_discovery(struct wl_priv *wl, struct net_device *dev,
+ const u8 *ie, u32 ie_len)
{
s32 ret = BCME_OK;
if (wl_get_p2p_status(wl, DISCOVERY_ON)) {
@@ -511,10 +688,10 @@ wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active,
wl_escan_params_t *eparams;
wlc_ssid_t ssid;
/* Scan parameters */
-#define P2PAPI_SCAN_NPROBES 4
-#define P2PAPI_SCAN_DWELL_TIME_MS 80
-#define P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS 100
-#define P2PAPI_SCAN_HOME_TIME_MS 10
+#define P2PAPI_SCAN_NPROBES 1
+#define P2PAPI_SCAN_DWELL_TIME_MS 50
+#define P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS 40
+#define P2PAPI_SCAN_HOME_TIME_MS 60
struct net_device *pri_dev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY);
wl_set_p2p_status(wl, SCANNING);
/* Allocate scan params which need space for 3 channels and 0 ssids */
@@ -530,7 +707,7 @@ wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active,
return -1;
}
memset(memblk, 0, memsize);
- memset(ioctlbuf, 0, sizeof(ioctlbuf));
+ memset(wl->ioctl_buf, 0, WLC_IOCTL_MAXLEN);
if (search_state == WL_P2P_DISC_ST_SEARCH) {
/*
* If we in SEARCH STATE, we don't need to set SSID explictly
@@ -569,7 +746,7 @@ wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active,
eparams->params.nprobes = htod32(P2PAPI_SCAN_NPROBES);
eparams->params.home_time = htod32(P2PAPI_SCAN_HOME_TIME_MS);
- if (wl_get_drv_status(wl, CONNECTED))
+ if (wl_get_drv_status_all(wl, CONNECTED))
eparams->params.active_time = htod32(-1);
else if (num_chans == 3)
eparams->params.active_time = htod32(P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS);
@@ -595,9 +772,54 @@ wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active,
CFGP2P_INFO(("\n"));
ret = wldev_iovar_setbuf_bsscfg(pri_dev, "p2p_scan",
- memblk, memsize, smbuf, sizeof(ioctlbuf), bssidx);
+ memblk, memsize, wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync);
return ret;
}
+
+/* search function to reach at common channel to send action frame
+ * Parameters:
+ * @wl : wl_private data
+ * @ndev : net device for bssidx
+ * @bssidx : bssidx for BSS
+ * Returns 0 if success.
+ */
+s32
+wl_cfgp2p_act_frm_search(struct wl_priv *wl, struct net_device *ndev,
+ s32 bssidx, s32 channel)
+{
+ s32 ret = 0;
+ u32 chan_cnt = 0;
+ u16 *default_chan_list = NULL;
+ if (!p2p_is_on(wl))
+ return -BCME_ERROR;
+ CFGP2P_ERR((" Enter\n"));
+ if (bssidx == P2PAPI_BSSCFG_PRIMARY)
+ bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE);
+ if (channel)
+ chan_cnt = 1;
+ else
+ chan_cnt = SOCIAL_CHAN_CNT;
+ default_chan_list = kzalloc(chan_cnt * sizeof(*default_chan_list), GFP_KERNEL);
+ if (default_chan_list == NULL) {
+ CFGP2P_ERR(("channel list allocation failed \n"));
+ ret = -ENOMEM;
+ goto exit;
+ }
+ if (channel) {
+ default_chan_list[0] = channel;
+ } else {
+ default_chan_list[0] = SOCIAL_CHAN_1;
+ default_chan_list[1] = SOCIAL_CHAN_2;
+ default_chan_list[2] = SOCIAL_CHAN_3;
+ }
+ ret = wl_cfgp2p_escan(wl, ndev, true, SOCIAL_CHAN_CNT,
+ default_chan_list, WL_P2P_DISC_ST_SEARCH,
+ WL_SCAN_ACTION_START, bssidx);
+ kfree(default_chan_list);
+exit:
+ return ret;
+}
+
/* Check whether pointed-to IE looks like WPA. */
#define wl_cfgp2p_is_wpa_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \
(const uint8 *)WPS_OUI, WPS_OUI_LEN, WPA_OUI_TYPE)
@@ -607,6 +829,10 @@ wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active,
/* Check whether the given IE looks like WFA P2P IE. */
#define wl_cfgp2p_is_p2p_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \
(const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_P2P)
+/* Check whether the given IE looks like WFA WFDisplay IE. */
+#define WFA_OUI_TYPE_WFD 0x0a /* WiFi Display OUI TYPE */
+#define wl_cfgp2p_is_wfd_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \
+ (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_WFD)
/* Delete and Set a management vndr ie to firmware
* Parameters:
* @wl : wl_private data
@@ -635,7 +861,7 @@ wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bss
u8 delete = 0;
#define IE_TYPE(type, bsstype) (wl_to_p2p_bss_saved_ie(wl, bsstype).p2p_ ## type ## _ie)
#define IE_TYPE_LEN(type, bsstype) (wl_to_p2p_bss_saved_ie(wl, bsstype).p2p_ ## type ## _ie_len)
- if (wl->p2p_supported && p2p_on(wl) && bssidx != -1) {
+ if (p2p_is_on(wl) && bssidx != -1) {
if (bssidx == P2PAPI_BSSCFG_PRIMARY)
bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE);
switch (pktflag) {
@@ -670,7 +896,7 @@ wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bss
CFGP2P_ERR(("not suitable type\n"));
return -1;
}
- } else if (get_mode_by_netdev(wl, ndev) == WL_MODE_AP) {
+ } else if (wl_get_mode_by_netdev(wl, ndev) == WL_MODE_AP) {
switch (pktflag) {
case VNDR_IE_PRBRSP_FLAG :
mgmt_ie_buf = wl->ap_info->probe_res_ie;
@@ -689,7 +915,7 @@ wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bss
return -1;
}
bssidx = 0;
- } else if (bssidx == -1 && get_mode_by_netdev(wl, ndev) == WL_MODE_BSS) {
+ } else if (bssidx == -1 && wl_get_mode_by_netdev(wl, ndev) == WL_MODE_BSS) {
switch (pktflag) {
case VNDR_IE_PRBREQ_FLAG :
mgmt_ie_buf = wl->sta_info->probe_req_ie;
@@ -731,12 +957,14 @@ wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bss
ie_len = ie_buf[pos++];
if ((ie_id == DOT11_MNG_VS_ID) &&
(wl_cfgp2p_is_wps_ie(&ie_buf[pos-2], NULL, 0) ||
- wl_cfgp2p_is_p2p_ie(&ie_buf[pos-2], NULL, 0))) {
+ wl_cfgp2p_is_p2p_ie(&ie_buf[pos-2], NULL, 0) ||
+ wl_cfgp2p_is_wfd_ie(&ie_buf[pos-2], NULL, 0))) {
CFGP2P_INFO(("DELELED ID : %d, Len : %d , OUI :"
"%02x:%02x:%02x\n", ie_id, ie_len, ie_buf[pos],
ie_buf[pos+1], ie_buf[pos+2]));
- ret = wl_cfgp2p_vndr_ie(ndev, bssidx, pktflag, ie_buf+pos,
- VNDR_SPEC_ELEMENT_ID, ie_buf+pos+3, ie_len-3, delete);
+ ret = wl_cfgp2p_vndr_ie(wl, ndev, bssidx, pktflag,
+ ie_buf+pos, VNDR_SPEC_ELEMENT_ID, ie_buf+pos+3,
+ ie_len-3, delete);
}
pos += ie_len;
}
@@ -756,12 +984,14 @@ wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bss
ie_len = ie_buf[pos++];
if ((ie_id == DOT11_MNG_VS_ID) &&
(wl_cfgp2p_is_wps_ie(&ie_buf[pos-2], NULL, 0) ||
- wl_cfgp2p_is_p2p_ie(&ie_buf[pos-2], NULL, 0))) {
+ wl_cfgp2p_is_p2p_ie(&ie_buf[pos-2], NULL, 0) ||
+ wl_cfgp2p_is_wfd_ie(&ie_buf[pos-2], NULL, 0))) {
CFGP2P_INFO(("ADDED ID : %d, Len : %d , OUI :"
"%02x:%02x:%02x\n", ie_id, ie_len, ie_buf[pos],
ie_buf[pos+1], ie_buf[pos+2]));
- ret = wl_cfgp2p_vndr_ie(ndev, bssidx, pktflag, ie_buf+pos,
- VNDR_SPEC_ELEMENT_ID, ie_buf+pos+3, ie_len-3, delete);
+ ret = wl_cfgp2p_vndr_ie(wl, ndev, bssidx, pktflag,
+ ie_buf+pos, VNDR_SPEC_ELEMENT_ID, ie_buf+pos+3,
+ ie_len-3, delete);
}
pos += ie_len;
}
@@ -865,9 +1095,21 @@ wl_cfgp2p_find_p2pie(u8 *parse, u32 len)
}
return NULL;
}
+wifi_wfd_ie_t *
+wl_cfgp2p_find_wfdie(u8 *parse, u32 len)
+{
+ bcm_tlv_t *ie;
+
+ while ((ie = bcm_parse_tlvs(parse, (int)len, DOT11_MNG_VS_ID))) {
+ if (wl_cfgp2p_is_wfd_ie((uint8*)ie, &parse, &len)) {
+ return (wifi_wfd_ie_t *)ie;
+ }
+ }
+ return NULL;
+}
static s32
-wl_cfgp2p_vndr_ie(struct net_device *ndev, s32 bssidx, s32 pktflag,
+wl_cfgp2p_vndr_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx, s32 pktflag,
s8 *oui, s32 ie_id, s8 *data, s32 data_len, s32 delete)
{
s32 err = BCME_OK;
@@ -909,7 +1151,7 @@ wl_cfgp2p_vndr_ie(struct net_device *ndev, s32 bssidx, s32 pktflag,
memcpy(ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, oui, 3);
memcpy(ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data, data, data_len);
err = wldev_iovar_setbuf_bsscfg(ndev, "vndr_ie", ie_setbuf, buf_len,
- ioctlbuf, sizeof(ioctlbuf), bssidx);
+ wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync);
CFGP2P_INFO(("vndr_ie iovar returns %d\n", err));
kfree(ie_setbuf);
@@ -957,14 +1199,17 @@ wl_cfgp2p_listen_complete(struct wl_priv *wl, struct net_device *ndev,
s32 ret = BCME_OK;
CFGP2P_DBG((" Enter\n"));
+
+ /* If p2p_info is de-initialized, do nothing */
+ if (!wl->p2p)
+ return ret;
+
if (wl_get_p2p_status(wl, LISTEN_EXPIRED) == 0) {
wl_set_p2p_status(wl, LISTEN_EXPIRED);
if (timer_pending(&wl->p2p->listen_timer)) {
- spin_lock_bh(&wl->p2p->timer_lock);
del_timer_sync(&wl->p2p->listen_timer);
- spin_unlock_bh(&wl->p2p->timer_lock);
}
- cfg80211_remain_on_channel_expired(ndev, wl->cache_cookie, &wl->remain_on_chan,
+ cfg80211_remain_on_channel_expired(ndev, wl->last_roc_id, &wl->remain_on_chan,
wl->remain_on_chan_type, GFP_KERNEL);
} else
wl_clr_p2p_status(wl, LISTEN_EXPIRED);
@@ -990,6 +1235,33 @@ wl_cfgp2p_listen_expired(unsigned long data)
}
/*
+ * Routine for cancelling the P2P LISTEN
+ */
+s32
+wl_cfgp2p_cancel_listen(struct wl_priv *wl, struct net_device *ndev,
+ bool notify)
+{
+ WL_DBG(("Enter \n"));
+
+ /* Irrespective of whether timer is running or not, reset
+ * the LISTEN state.
+ */
+ wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0,
+ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE));
+
+ if (timer_pending(&wl->p2p->listen_timer)) {
+ del_timer_sync(&wl->p2p->listen_timer);
+
+ if (notify)
+ cfg80211_remain_on_channel_expired(ndev, wl->last_roc_id,
+ &wl->remain_on_chan, wl->remain_on_chan_type, GFP_KERNEL);
+ }
+
+
+ return 0;
+}
+
+/*
* Do a P2P Listen on the given channel for the given duration.
* A listen consists of sitting idle and responding to P2P probe requests
* with a P2P probe response.
@@ -1093,10 +1365,10 @@ wl_cfgp2p_action_tx_complete(struct wl_priv *wl, struct net_device *ndev,
wl_set_p2p_status(wl, ACTION_TX_NOACK);
CFGP2P_ERR(("WLC_E_ACTION_FRAME_COMPLETE : NO ACK\n"));
}
- wake_up_interruptible(&wl->dongle_event_wait);
} else {
CFGP2P_INFO((" WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE is received,"
"status : %d\n", status));
+ wake_up_interruptible(&wl->netif_change_event);
}
return ret;
}
@@ -1126,15 +1398,15 @@ wl_cfgp2p_tx_action_frame(struct wl_priv *wl, struct net_device *dev,
if (bssidx == P2PAPI_BSSCFG_PRIMARY)
bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE);
- ret = wldev_iovar_setbuf_bsscfg(dev, "actframe",
- af_params, sizeof(*af_params), ioctlbuf, sizeof(ioctlbuf), bssidx);
+ ret = wldev_iovar_setbuf_bsscfg(dev, "actframe", af_params, sizeof(*af_params),
+ wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync);
if (ret < 0) {
CFGP2P_ERR((" sending action frame is failed\n"));
goto exit;
}
- timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
+ timeout = wait_event_interruptible_timeout(wl->netif_change_event,
(wl_get_p2p_status(wl, ACTION_TX_COMPLETED) || wl_get_p2p_status(wl, ACTION_TX_NOACK)),
msecs_to_jiffies(MAX_WAIT_TIME));
@@ -1243,7 +1515,7 @@ wl_cfgp2p_bss_isup(struct net_device *ndev, int bsscfg_idx)
/* Check if the BSS is up */
*(int*)getbuf = -1;
result = wldev_iovar_getbuf_bsscfg(ndev, "bss", &bsscfg_idx,
- sizeof(bsscfg_idx), getbuf, sizeof(getbuf), 0);
+ sizeof(bsscfg_idx), getbuf, sizeof(getbuf), 0, NULL);
if (result != 0) {
CFGP2P_ERR(("'wl bss -C %d' failed: %d\n", bsscfg_idx, result));
CFGP2P_ERR(("NOTE: this ioctl error is normal "
@@ -1260,7 +1532,7 @@ wl_cfgp2p_bss_isup(struct net_device *ndev, int bsscfg_idx)
/* Bring up or down a BSS */
s32
-wl_cfgp2p_bss(struct net_device *ndev, s32 bsscfg_idx, s32 up)
+wl_cfgp2p_bss(struct wl_priv *wl, struct net_device *ndev, s32 bsscfg_idx, s32 up)
{
s32 ret = BCME_OK;
s32 val = up ? 1 : 0;
@@ -1274,7 +1546,7 @@ wl_cfgp2p_bss(struct net_device *ndev, s32 bsscfg_idx, s32 up)
bss_setbuf.val = htod32(val);
CFGP2P_INFO(("---wl bss -C %d %s\n", bsscfg_idx, up ? "up" : "down"));
ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf),
- ioctlbuf, sizeof(ioctlbuf));
+ wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync);
if (ret != 0) {
CFGP2P_ERR(("'bss %d' failed with %d\n", up, ret));
@@ -1308,13 +1580,16 @@ wl_cfgp2p_supported(struct wl_priv *wl, struct net_device *ndev)
s32
wl_cfgp2p_down(struct wl_priv *wl)
{
- if (timer_pending(&wl->p2p->listen_timer))
- del_timer_sync(&wl->p2p->listen_timer);
+
+ wl_cfgp2p_cancel_listen(wl,
+ wl->p2p_net ? wl->p2p_net : wl_to_prmry_ndev(wl), TRUE);
+
wl_cfgp2p_deinit_priv(wl);
return 0;
}
-s32 wl_cfgp2p_set_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int len)
+s32
+wl_cfgp2p_set_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int len)
{
s32 ret = -1;
int count, start, duration;
@@ -1330,7 +1605,7 @@ s32 wl_cfgp2p_set_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf
sscanf(buf, "%d %d %d", &count, &start, &duration);
CFGP2P_DBG(("set_p2p_noa count %d start %d duration %d\n",
- count, start, duration));
+ count, start, duration));
if (count != -1)
wl->p2p->noa.desc[0].count = count;
@@ -1374,7 +1649,8 @@ s32 wl_cfgp2p_set_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf
dongle_noa.desc[0].interval = htod32(wl->p2p->noa.desc[0].interval*1000);
ret = wldev_iovar_setbuf(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION),
- "p2p_noa", &dongle_noa, sizeof(dongle_noa), ioctlbuf, sizeof(ioctlbuf));
+ "p2p_noa", &dongle_noa, sizeof(dongle_noa), wl->ioctl_buf, WLC_IOCTL_MAXLEN,
+ &wl->ioctl_buf_sync);
if (ret < 0) {
CFGP2P_ERR(("fw set p2p_noa failed %d\n", ret));
@@ -1386,7 +1662,8 @@ s32 wl_cfgp2p_set_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf
return ret;
}
-s32 wl_cfgp2p_get_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int buf_len)
+s32
+wl_cfgp2p_get_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int buf_len)
{
wifi_p2p_noa_desc_t *noa_desc;
int len = 0, i;
@@ -1428,7 +1705,8 @@ s32 wl_cfgp2p_get_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf
return len * 2;
}
-s32 wl_cfgp2p_set_p2p_ps(struct wl_priv *wl, struct net_device *ndev, char* buf, int len)
+s32
+wl_cfgp2p_set_p2p_ps(struct wl_priv *wl, struct net_device *ndev, char* buf, int len)
{
int ps, ctw;
int ret = -1;
@@ -1446,7 +1724,7 @@ s32 wl_cfgp2p_set_p2p_ps(struct wl_priv *wl, struct net_device *ndev, char* buf,
wl->p2p->ops.ops = ps;
ret = wldev_iovar_setbuf(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION),
"p2p_ops", &wl->p2p->ops, sizeof(wl->p2p->ops),
- ioctlbuf, sizeof(ioctlbuf));
+ wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync);
if (ret < 0) {
CFGP2P_ERR(("fw set p2p_ops failed %d\n", ret));
}
@@ -1467,3 +1745,257 @@ s32 wl_cfgp2p_set_p2p_ps(struct wl_priv *wl, struct net_device *ndev, char* buf,
}
return ret;
}
+
+u8 *
+wl_cfgp2p_retreive_p2pattrib(void *buf, u8 element_id)
+{
+ wifi_p2p_ie_t *ie = NULL;
+ u16 len = 0;
+ u8 *subel;
+ u8 subelt_id;
+ u16 subelt_len;
+
+ if (!buf) {
+ WL_ERR(("P2P IE not present"));
+ return 0;
+ }
+
+ ie = (wifi_p2p_ie_t*) buf;
+ len = ie->len;
+
+ /* Point subel to the P2P IE's subelt field.
+ * Subtract the preceding fields (id, len, OUI, oui_type) from the length.
+ */
+ subel = ie->subelts;
+ len -= 4; /* exclude OUI + OUI_TYPE */
+
+ while (len >= 3) {
+ /* attribute id */
+ subelt_id = *subel;
+ subel += 1;
+ len -= 1;
+
+ /* 2-byte little endian */
+ subelt_len = *subel++;
+ subelt_len |= *subel++ << 8;
+
+ len -= 2;
+ len -= subelt_len; /* for the remaining subelt fields */
+
+ if (subelt_id == element_id) {
+ /* This will point to start of subelement attrib after
+ * attribute id & len
+ */
+ return subel;
+ }
+
+ /* Go to next subelement */
+ subel += subelt_len;
+ }
+
+ /* Not Found */
+ return NULL;
+}
+
+#define P2P_GROUP_CAPAB_GO_BIT 0x01
+u8 *
+wl_cfgp2p_retreive_p2p_dev_addr(wl_bss_info_t *bi, u32 bi_length)
+{
+ wifi_p2p_ie_t * p2p_ie = NULL;
+ u8 *capability = NULL;
+ bool p2p_go = 0;
+ u8 *ptr = NULL;
+
+ if (!(p2p_ie = wl_cfgp2p_find_p2pie(((u8 *) bi) + bi->ie_offset, bi->ie_length))) {
+ WL_ERR(("P2P IE not found"));
+ return NULL;
+ }
+
+ if (!(capability = wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_P2P_INFO))) {
+ WL_ERR(("P2P Capability attribute not found"));
+ return NULL;
+ }
+
+ /* Check Group capability for Group Owner bit */
+ p2p_go = capability[1] & P2P_GROUP_CAPAB_GO_BIT;
+ if (!p2p_go) {
+ return bi->BSSID.octet;
+ }
+
+ /* In probe responses, DEVICE INFO attribute will be present */
+ if (!(ptr = wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_DEV_INFO))) {
+ /* If DEVICE_INFO is not found, this might be a beacon frame.
+ * check for DEVICE_ID in the beacon frame.
+ */
+ ptr = wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_DEV_ID);
+ }
+
+ if (!ptr)
+ WL_ERR((" Both DEVICE_ID & DEVICE_INFO attribute not present in P2P IE "));
+
+ return ptr;
+}
+
+s32
+wl_cfgp2p_register_ndev(struct wl_priv *wl)
+{
+ int ret = 0;
+ struct net_device* net = NULL;
+ struct wireless_dev *wdev;
+ uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x33, 0x22, 0x11 };
+
+ /* Allocate etherdev, including space for private structure */
+ if (!(net = alloc_etherdev(sizeof(wl)))) {
+ CFGP2P_ERR(("%s: OOM - alloc_etherdev\n", __FUNCTION__));
+ goto fail;
+ }
+
+ strcpy(net->name, "p2p%d");
+ net->name[IFNAMSIZ - 1] = '\0';
+
+ /* Copy the reference to wl_priv */
+ memcpy((void *)netdev_priv(net), &wl, sizeof(wl));
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31))
+ ASSERT(!net->open);
+ net->do_ioctl = wl_cfgp2p_do_ioctl;
+ net->hard_start_xmit = wl_cfgp2p_start_xmit;
+ net->open = wl_cfgp2p_if_open;
+ net->stop = wl_cfgp2p_if_stop;
+#else
+ ASSERT(!net->netdev_ops);
+ net->netdev_ops = &wl_cfgp2p_if_ops;
+#endif
+
+ /* Register with a dummy MAC addr */
+ memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN);
+
+ wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
+ if (unlikely(!wdev)) {
+ WL_ERR(("Could not allocate wireless device\n"));
+ return -ENOMEM;
+ }
+
+ wdev->wiphy = wl->wdev->wiphy;
+
+ wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS);
+
+ net->ieee80211_ptr = wdev;
+
+ SET_NETDEV_DEV(net, wiphy_dev(wdev->wiphy));
+
+ /* Associate p2p0 network interface with new wdev */
+ wdev->netdev = net;
+
+ /* store p2p net ptr for further reference. Note that iflist won't have this
+ * entry as there corresponding firmware interface is a "Hidden" interface.
+ */
+ if (wl->p2p_net) {
+ CFGP2P_ERR(("p2p_net defined already.\n"));
+ return -EINVAL;
+ } else {
+ wl->p2p_wdev = wdev;
+ wl->p2p_net = net;
+ }
+
+ ret = register_netdev(net);
+ if (ret) {
+ CFGP2P_ERR((" register_netdevice failed (%d)\n", ret));
+ goto fail;
+ }
+
+ printk("%s: P2P Interface Registered\n", net->name);
+
+ return ret;
+fail:
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
+ net->open = NULL;
+#else
+ net->netdev_ops = NULL;
+#endif
+
+ if (net) {
+ unregister_netdev(net);
+ free_netdev(net);
+ }
+
+ return -ENODEV;
+}
+
+s32
+wl_cfgp2p_unregister_ndev(struct wl_priv *wl)
+{
+
+ if (!wl || !wl->p2p_net) {
+ CFGP2P_ERR(("Invalid Ptr\n"));
+ return -EINVAL;
+ }
+
+ unregister_netdev(wl->p2p_net);
+ free_netdev(wl->p2p_net);
+
+ return 0;
+}
+
+static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ CFGP2P_DBG(("(%s) is not used for data operations. Droping the packet. \n", ndev->name));
+ return 0;
+}
+
+static int wl_cfgp2p_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd)
+{
+ int ret = 0;
+ struct wl_priv *wl = *(struct wl_priv **)netdev_priv(net);
+ struct net_device *ndev = wl_to_prmry_ndev(wl);
+
+ /* There is no ifidx corresponding to p2p0 in our firmware. So we should
+ * not Handle any IOCTL cmds on p2p0 other than ANDROID PRIVATE CMDs.
+ * For Android PRIV CMD handling map it to primary I/F
+ */
+ if (cmd == SIOCDEVPRIVATE+1) {
+ ret = wl_android_priv_cmd(ndev, ifr, cmd);
+
+ } else {
+ CFGP2P_ERR(("%s: IOCTL req 0x%x on p2p0 I/F. Ignoring. \n",
+ __FUNCTION__, cmd));
+ return -1;
+ }
+
+ return ret;
+}
+
+static int wl_cfgp2p_if_open(struct net_device *net)
+{
+ struct wireless_dev *wdev = net->ieee80211_ptr;
+
+ if (!wdev)
+ return -EINVAL;
+
+ /* If suppose F/W download (ifconfig wlan0 up) hasn't been done by now,
+ * do it here. This will make sure that in concurrent mode, supplicant
+ * is not dependent on a particular order of interface initialization.
+ * i.e you may give wpa_supp -iwlan0 -N -ip2p0 or wpa_supp -ip2p0 -N
+ * -iwlan0.
+ */
+ wl_cfg80211_do_driver_init(net);
+
+ wdev->wiphy->interface_modes |= (BIT(NL80211_IFTYPE_P2P_CLIENT)
+ | BIT(NL80211_IFTYPE_P2P_GO));
+
+ return 0;
+}
+
+static int wl_cfgp2p_if_stop(struct net_device *net)
+{
+ struct wireless_dev *wdev = net->ieee80211_ptr;
+
+ if (!wdev)
+ return -EINVAL;
+
+ wdev->wiphy->interface_modes = (wdev->wiphy->interface_modes)
+ & (~(BIT(NL80211_IFTYPE_P2P_CLIENT)|
+ BIT(NL80211_IFTYPE_P2P_GO)));
+ return 0;
+}
diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h
index 5a69168c6a3a..668198d31a2e 100644
--- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h
+++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h
@@ -30,7 +30,7 @@
struct wl_priv;
extern u32 wl_dbg_level;
-
+typedef struct wifi_p2p_ie wifi_wfd_ie_t;
/* Enumeration of the usages of the BSSCFGs used by the P2P Library. Do not
* confuse this with a bsscfg index. This value is an index into the
* saved_ie[] array of structures which in turn contains a bsscfg index field.
@@ -77,7 +77,6 @@ struct p2p_info {
wl_p2p_sched_t noa;
wl_p2p_ops_t ops;
wlc_ssid_t ssid;
- spinlock_t timer_lock;
};
/* dongle status */
@@ -101,13 +100,13 @@ enum wl_cfgp2p_status {
#define wl_to_p2p_bss_saved_ie(w, type) ((wl)->p2p->bss_idx[type].saved_ie)
#define wl_to_p2p_bss_private(w, type) ((wl)->p2p->bss_idx[type].private_data)
#define wl_to_p2p_bss(wl, type) ((wl)->p2p->bss_idx[type])
-#define wl_get_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0 : test_bit(WLP2P_STATUS_ ## stat, \
+#define wl_get_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0:test_bit(WLP2P_STATUS_ ## stat, \
&(wl)->p2p->status))
-#define wl_set_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? : set_bit(WLP2P_STATUS_ ## stat, \
+#define wl_set_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0:set_bit(WLP2P_STATUS_ ## stat, \
&(wl)->p2p->status))
-#define wl_clr_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? : clear_bit(WLP2P_STATUS_ ## stat, \
+#define wl_clr_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0:clear_bit(WLP2P_STATUS_ ## stat, \
&(wl)->p2p->status))
-#define wl_chg_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? : change_bit(WLP2P_STATUS_ ## stat, \
+#define wl_chg_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0:change_bit(WLP2P_STATUS_ ## stat, \
&(wl)->p2p->status))
#define p2p_on(wl) ((wl)->p2p->on)
#define p2p_scan(wl) ((wl)->p2p->scan)
@@ -140,7 +139,14 @@ enum wl_cfgp2p_status {
} \
} while (0)
-
+extern bool
+wl_cfgp2p_is_pub_action(void *frame, u32 frame_len);
+extern bool
+wl_cfgp2p_is_p2p_action(void *frame, u32 frame_len);
+extern bool
+wl_cfgp2p_is_gas_action(void *frame, u32 frame_len);
+extern void
+wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len);
extern s32
wl_cfgp2p_init_priv(struct wl_priv *wl);
extern void
@@ -172,6 +178,10 @@ wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active, u32 num_
u16 *channels,
s32 search_state, u16 action, u32 bssidx);
+extern s32
+wl_cfgp2p_act_frm_search(struct wl_priv *wl, struct net_device *ndev,
+ s32 bssidx, s32 channel);
+
extern wpa_ie_fixed_t *
wl_cfgp2p_find_wpaie(u8 *parse, u32 len);
@@ -181,6 +191,9 @@ wl_cfgp2p_find_wpsie(u8 *parse, u32 len);
extern wifi_p2p_ie_t *
wl_cfgp2p_find_p2pie(u8 *parse, u32 len);
+extern wifi_wfd_ie_t *
+wl_cfgp2p_find_wfdie(u8 *parse, u32 len);
+
extern s32
wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx,
s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len);
@@ -217,7 +230,7 @@ extern bool
wl_cfgp2p_bss_isup(struct net_device *ndev, int bsscfg_idx);
extern s32
-wl_cfgp2p_bss(struct net_device *ndev, s32 bsscfg_idx, s32 up);
+wl_cfgp2p_bss(struct wl_priv *wl, struct net_device *ndev, s32 bsscfg_idx, s32 up);
extern s32
@@ -235,13 +248,38 @@ wl_cfgp2p_get_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, in
extern s32
wl_cfgp2p_set_p2p_ps(struct wl_priv *wl, struct net_device *ndev, char* buf, int len);
+extern u8 *
+wl_cfgp2p_retreive_p2pattrib(void *buf, u8 element_id);
+
+extern u8 *
+wl_cfgp2p_retreive_p2p_dev_addr(wl_bss_info_t *bi, u32 bi_length);
+
+extern s32
+wl_cfgp2p_register_ndev(struct wl_priv *wl);
+
+extern s32
+wl_cfgp2p_unregister_ndev(struct wl_priv *wl);
+
/* WiFi Direct */
#define SOCIAL_CHAN_1 1
#define SOCIAL_CHAN_2 6
#define SOCIAL_CHAN_3 11
+#define SOCIAL_CHAN_CNT 3
#define WL_P2P_WILDCARD_SSID "DIRECT-"
#define WL_P2P_WILDCARD_SSID_LEN 7
#define WL_P2P_INTERFACE_PREFIX "p2p"
#define WL_P2P_TEMP_CHAN "11"
+
+/* If the provision discovery is for JOIN operations, then we need not do an internal scan to find GO */
+#define IS_PROV_DISC_WITHOUT_GROUP_ID(p2p_ie, len) (wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_GROUP_ID) == NULL )
+
+#define IS_GAS_REQ(frame, len) (wl_cfgp2p_is_gas_action(frame, len) && \
+ ((frame->action == P2PSD_ACTION_ID_GAS_IREQ) || \
+ (frame->action == P2PSD_ACTION_ID_GAS_CREQ)))
+#define IS_P2P_PUB_ACT_REQ(frame, p2p_ie, len) (wl_cfgp2p_is_pub_action(frame, len) && \
+ ((frame->subtype == P2P_PAF_GON_REQ) || \
+ (frame->subtype == P2P_PAF_INVITE_REQ) || \
+ ((frame->subtype == P2P_PAF_PROVDIS_REQ) && IS_PROV_DISC_WITHOUT_GROUP_ID(p2p_ie, len))))
+#define IS_P2P_SOCIAL(ch) ((ch == SOCIAL_CHAN_1) || (ch == SOCIAL_CHAN_2) || (ch == SOCIAL_CHAN_3))
#define IS_P2P_SSID(ssid) (memcmp(ssid, WL_P2P_WILDCARD_SSID, WL_P2P_WILDCARD_SSID_LEN) == 0)
#endif /* _wl_cfgp2p_h_ */
diff --git a/drivers/net/wireless/bcmdhd/wl_iw.c b/drivers/net/wireless/bcmdhd/wl_iw.c
index 457372b62b3a..059929340354 100644
--- a/drivers/net/wireless/bcmdhd/wl_iw.c
+++ b/drivers/net/wireless/bcmdhd/wl_iw.c
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: wl_iw.c,v 1.132.2.18 2011-02-05 01:44:47 Exp $
+ * $Id: wl_iw.c,v 1.132.2.18 2011-02-05 01:44:47 $
*/
#include <wlioctl.h>
@@ -148,7 +148,7 @@ static struct mutex wl_softap_lock;
#include <bcmsdbus.h>
extern void dhd_customer_gpio_wlan_ctrl(int onoff);
extern uint dhd_dev_reset(struct net_device *dev, uint8 flag);
-extern void dhd_dev_init_ioctl(struct net_device *dev);
+extern int dhd_dev_init_ioctl(struct net_device *dev);
uint wl_msg_level = WL_ERROR_VAL;
@@ -162,11 +162,8 @@ uint wl_msg_level = WL_ERROR_VAL;
#define htodchanspec(i) i
#define dtohchanspec(i) i
-#ifdef CONFIG_WIRELESS_EXT
-
extern struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev);
extern int dhd_wait_pend8021x(struct net_device *dev);
-#endif
#if WIRELESS_EXT < 19
#define IW_IOCTL_IDX(cmd) ((cmd) - SIOCIWFIRST)
@@ -1122,7 +1119,7 @@ wl_iw_set_btcoex_dhcp(
}
static int
-wl_iw_set_suspend(
+wl_iw_set_suspend_opt(
struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
@@ -1133,16 +1130,15 @@ char *extra
int ret_now;
int ret = 0;
- suspend_flag = *(extra + strlen(SETSUSPEND_CMD) + 1) - '0';
+ suspend_flag = *(extra + strlen(SETSUSPENDOPT_CMD) + 1) - '0';
if (suspend_flag != 0)
suspend_flag = 1;
ret_now = net_os_set_suspend_disable(dev, suspend_flag);
-
if (ret_now != suspend_flag) {
- if (!(ret = net_os_set_suspend(dev, ret_now)))
+ if (!(ret = net_os_set_suspend(dev, ret_now, 1)))
WL_ERROR(("%s: Suspend Flag %d -> %d\n",
__FUNCTION__, ret_now, suspend_flag));
else
@@ -1153,6 +1149,32 @@ char *extra
}
static int
+wl_iw_set_suspend_mode(
+struct net_device *dev,
+struct iw_request_info *info,
+union iwreq_data *wrqu,
+char *extra
+)
+{
+ int ret = 0;
+
+#if !defined(CONFIG_HAS_EARLYSUSPEND) || !defined(DHD_USE_EARLYSUSPEND)
+ int suspend_flag;
+
+ suspend_flag = *(extra + strlen(SETSUSPENDMODE_CMD) + 1) - '0';
+
+ if (suspend_flag != 0)
+ suspend_flag = 1;
+
+ if (!(ret = net_os_set_suspend(dev, suspend_flag, 0)))
+ WL_ERROR(("%s: Suspend Mode %d\n",__FUNCTION__,suspend_flag));
+ else
+ WL_ERROR(("%s: failed %d\n", __FUNCTION__, ret));
+#endif
+ return ret;
+}
+
+static int
wl_format_ssid(char* ssid_buf, uint8* ssid, int ssid_len)
{
int i, c;
@@ -1564,6 +1586,63 @@ exit_proc:
net_os_wake_unlock(dev);
return res;
}
+
+static int
+wl_iw_set_pno_setadd(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra
+)
+{
+ int ret = -1;
+ char *tmp_ptr;
+ int size, tmp_size;
+
+ net_os_wake_lock(dev);
+ WL_ERROR(("\n### %s: info->cmd:%x, info->flags:%x, u.data=0x%p, u.len=%d\n",
+ __FUNCTION__, info->cmd, info->flags,
+ wrqu->data.pointer, wrqu->data.length));
+
+ if (g_onoff == G_WLAN_SET_OFF) {
+ WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__));
+ goto exit_proc;
+ }
+
+ if (wrqu->data.length <= strlen(PNOSETADD_SET_CMD) + sizeof(cmd_tlv_t)) {
+ WL_ERROR(("%s argument=%d less than %d\n", __FUNCTION__,
+ wrqu->data.length, (int)(strlen(PNOSETADD_SET_CMD) + sizeof(cmd_tlv_t))));
+ goto exit_proc;
+ }
+
+
+ bcopy(PNOSETUP_SET_CMD, extra, strlen(PNOSETUP_SET_CMD));
+
+ tmp_ptr = extra + strlen(PNOSETUP_SET_CMD);
+ size = wrqu->data.length - strlen(PNOSETUP_SET_CMD);
+ tmp_size = size;
+
+ while (*tmp_ptr && tmp_size > 0) {
+ if ((*tmp_ptr == 'S') && (size - tmp_size) >= sizeof(cmd_tlv_t)) {
+ *(tmp_ptr + 1) = ((*(tmp_ptr + 1) - '0') << 4) + (*(tmp_ptr + 2) - '0');
+ memmove(tmp_ptr + 2, tmp_ptr + 3, tmp_size - 3);
+ tmp_size -= 2 + *(tmp_ptr + 1);
+ tmp_ptr += 2 + *(tmp_ptr + 1);
+ size--;
+ } else {
+ tmp_ptr++;
+ tmp_size--;
+ }
+ }
+
+ wrqu->data.length = strlen(PNOSETUP_SET_CMD) + size;
+ ret = wl_iw_set_pno_set(dev, info, wrqu, extra);
+
+exit_proc:
+ net_os_wake_unlock(dev);
+ return ret;
+
+}
#endif
static int
@@ -1626,7 +1705,7 @@ wl_iw_send_priv_event(
strcpy(extra, flag);
wrqu.data.length = strlen(extra);
wireless_send_event(dev, cmd, &wrqu, extra);
- net_os_wake_lock_timeout_enable(dev, DHD_EVENT_TIMEOUT);
+ net_os_wake_lock_ctrl_timeout_enable(dev, DHD_EVENT_TIMEOUT_MS);
WL_TRACE(("Send IWEVCUSTOM Event as %s\n", extra));
return 0;
@@ -2567,6 +2646,8 @@ wl_iw_get_range(
IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP);
IW_EVENT_CAPA_SET(range->event_capa, IWEVMICHAELMICFAILURE);
+ IW_EVENT_CAPA_SET(range->event_capa, IWEVASSOCREQIE);
+ IW_EVENT_CAPA_SET(range->event_capa, IWEVASSOCRESPIE);
IW_EVENT_CAPA_SET(range->event_capa, IWEVPMKIDCAND);
#endif
@@ -5473,7 +5554,15 @@ wl_iw_set_wpaauth(
switch (paramid) {
case IW_AUTH_WPA_VERSION:
- iw->wpaversion = paramval;
+ if (paramval & IW_AUTH_WPA_VERSION_DISABLED)
+ val = WPA_AUTH_DISABLED;
+ else if (paramval & (IW_AUTH_WPA_VERSION_WPA))
+ val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
+ else if (paramval & IW_AUTH_WPA_VERSION_WPA2)
+ val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
+ WL_ERROR(("%s: %d: setting wpa_auth to 0x%0x\n", __FUNCTION__, __LINE__, val));
+ if ((error = dev_wlc_intvar_set(dev, "wpa_auth", val)))
+ return error;
break;
case IW_AUTH_CIPHER_PAIRWISE:
@@ -5491,7 +5580,27 @@ wl_iw_set_wpaauth(
break;
case IW_AUTH_KEY_MGMT:
- if (paramval & IW_AUTH_KEY_MGMT_PSK) {
+ if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val)))
+ return error;
+
+ if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
+ if (paramval & IW_AUTH_KEY_MGMT_PSK)
+ val = WPA_AUTH_PSK;
+ else
+ val = WPA_AUTH_UNSPECIFIED;
+ if (paramval & 0x04)
+ val |= WPA2_AUTH_FT;
+ }
+ else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
+ if (paramval & IW_AUTH_KEY_MGMT_PSK)
+ val = WPA2_AUTH_PSK;
+ else
+ val = WPA2_AUTH_UNSPECIFIED;
+ if (paramval & 0x04)
+ val |= WPA2_AUTH_FT;
+ }
+
+ else if (paramval & IW_AUTH_KEY_MGMT_PSK) {
if (iw->wpaversion == IW_AUTH_WPA_VERSION_WPA)
val = WPA_AUTH_PSK;
else if (iw->wpaversion == IW_AUTH_WPA_VERSION_WPA2)
@@ -7517,8 +7626,10 @@ wl_iw_set_priv(
ret = wl_iw_get_dtim_skip(dev, info, (union iwreq_data *)dwrq, extra);
else if (strnicmp(extra, DTIM_SKIP_SET_CMD, strlen(DTIM_SKIP_SET_CMD)) == 0)
ret = wl_iw_set_dtim_skip(dev, info, (union iwreq_data *)dwrq, extra);
- else if (strnicmp(extra, SETSUSPEND_CMD, strlen(SETSUSPEND_CMD)) == 0)
- ret = wl_iw_set_suspend(dev, info, (union iwreq_data *)dwrq, extra);
+ else if (strnicmp(extra, SETSUSPENDOPT_CMD, strlen(SETSUSPENDOPT_CMD)) == 0)
+ ret = wl_iw_set_suspend_opt(dev, info, (union iwreq_data *)dwrq, extra);
+ else if (strnicmp(extra, SETSUSPENDMODE_CMD, strlen(SETSUSPENDMODE_CMD)) == 0)
+ ret = wl_iw_set_suspend_mode(dev, info, (union iwreq_data *)dwrq, extra);
else if (strnicmp(extra, TXPOWER_SET_CMD, strlen(TXPOWER_SET_CMD)) == 0)
ret = wl_iw_set_txpower(dev, info, (union iwreq_data *)dwrq, extra);
#if defined(PNO_SUPPORT)
@@ -7526,6 +7637,8 @@ wl_iw_set_priv(
ret = wl_iw_set_pno_reset(dev, info, (union iwreq_data *)dwrq, extra);
else if (strnicmp(extra, PNOSETUP_SET_CMD, strlen(PNOSETUP_SET_CMD)) == 0)
ret = wl_iw_set_pno_set(dev, info, (union iwreq_data *)dwrq, extra);
+ else if (strnicmp(extra, PNOSETADD_SET_CMD, strlen(PNOSETADD_SET_CMD)) == 0)
+ ret = wl_iw_set_pno_setadd(dev, info, (union iwreq_data *)dwrq, extra);
else if (strnicmp(extra, PNOENABLE_SET_CMD, strlen(PNOENABLE_SET_CMD)) == 0)
ret = wl_iw_set_pno_enable(dev, info, (union iwreq_data *)dwrq, extra);
#endif
@@ -8251,6 +8364,21 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data)
break;
}
+
+ case WLC_E_ASSOC_REQ_IE:
+ cmd = IWEVASSOCREQIE;
+ wrqu.data.length = datalen;
+ if (datalen < sizeof(extra))
+ memcpy(extra, data, datalen);
+ break;
+
+ case WLC_E_ASSOC_RESP_IE:
+ cmd = IWEVASSOCRESPIE;
+ wrqu.data.length = datalen;
+ if (datalen < sizeof(extra))
+ memcpy(extra, data, datalen);
+ break;
+
case WLC_E_PMKID_CACHE: {
if (data)
{
diff --git a/drivers/net/wireless/bcmdhd/wl_iw.h b/drivers/net/wireless/bcmdhd/wl_iw.h
index c0cc14bdde4e..9cdb53dfef8c 100644
--- a/drivers/net/wireless/bcmdhd/wl_iw.h
+++ b/drivers/net/wireless/bcmdhd/wl_iw.h
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: wl_iw.h,v 1.15.80.6 2010-12-23 01:13:23 Exp $
+ * $Id: wl_iw.h,v 1.15.80.6 2010-12-23 01:13:23 $
*/
@@ -47,13 +47,15 @@
#define BAND_SET_CMD "SETBAND"
#define DTIM_SKIP_GET_CMD "DTIMSKIPGET"
#define DTIM_SKIP_SET_CMD "DTIMSKIPSET"
-#define SETSUSPEND_CMD "SETSUSPENDOPT"
+#define SETSUSPENDOPT_CMD "SETSUSPENDOPT"
+#define SETSUSPENDMODE_CMD "SETSUSPENDMODE"
#define PNOSSIDCLR_SET_CMD "PNOSSIDCLR"
#define PNOSETUP_SET_CMD "PNOSETUP "
+#define PNOSETADD_SET_CMD "PNOSETADD"
#define PNOENABLE_SET_CMD "PNOFORCE"
#define PNODEBUG_SET_CMD "PNODEBUG"
-#define TXPOWER_SET_CMD "TXPOWER"
+#define TXPOWER_SET_CMD "TXPOWER"
#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
@@ -203,11 +205,10 @@ void wl_iw_detach(void);
extern int net_os_wake_lock(struct net_device *dev);
extern int net_os_wake_unlock(struct net_device *dev);
extern int net_os_wake_lock_timeout(struct net_device *dev);
-extern int net_os_wake_lock_timeout_enable(struct net_device *dev, int val);
+extern int net_os_wake_lock_ctrl_timeout_enable(struct net_device *dev, int val);
extern int net_os_set_suspend_disable(struct net_device *dev, int val);
-extern int net_os_set_suspend(struct net_device *dev, int val);
+extern int net_os_set_suspend(struct net_device *dev, int val, int force);
extern int net_os_set_dtim_skip(struct net_device *dev, int val);
-extern int net_os_send_hang_message(struct net_device *dev);
extern void get_customized_country_code(char *country_iso_code, wl_country_t *cspec);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
@@ -226,6 +227,18 @@ extern void get_customized_country_code(char *country_iso_code, wl_country_t *cs
iwe_stream_add_point(stream, ends, iwe, extra)
#endif
+extern int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled);
+extern int dhd_pno_clean(dhd_pub_t *dhd);
+extern int dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid,
+ ushort scan_fr, int pno_repeat, int pno_freq_expo_max);
+extern int dhd_pno_get_status(dhd_pub_t *dhd);
+extern int dhd_dev_pno_reset(struct net_device *dev);
+extern int dhd_dev_pno_set(struct net_device *dev, wlc_ssid_t* ssids_local,
+ int nssid, ushort scan_fr, int pno_repeat, int pno_freq_expo_max);
+extern int dhd_dev_pno_enable(struct net_device *dev, int pfn_enabled);
+extern int dhd_dev_get_pno_status(struct net_device *dev);
+extern int dhd_get_dtim_skip(dhd_pub_t *dhd);
+
void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec);
#define PNO_TLV_PREFIX 'S'
diff --git a/drivers/net/wireless/bcmdhd/wl_linux_mon.c b/drivers/net/wireless/bcmdhd/wl_linux_mon.c
new file mode 100644
index 000000000000..f44b4b04bb96
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/wl_linux_mon.c
@@ -0,0 +1,409 @@
+/*
+ * Broadcom Dongle Host Driver (DHD), Linux monitor network interface
+ *
+ * Copyright (C) 1999-2011, Broadcom Corporation
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2 (the "GPL"),
+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the
+ * following added to such license:
+ *
+ * As a special exception, the copyright holders of this software give you
+ * permission to link this software with independent modules, and to copy and
+ * distribute the resulting executable under terms of your choice, provided that
+ * you also meet, for each linked independent module, the terms and conditions of
+ * the license of that module. An independent module is a module which is not
+ * derived from this software. The special exception does not apply to any
+ * modifications of the software.
+ *
+ * Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a license
+ * other than the GPL, without Broadcom's express prior written consent.
+ *
+ * $Id: wl_linux_mon.c 303266 2011-12-16 00:15:23Z $
+ */
+
+#include <linux/string.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+#include <linux/ieee80211.h>
+#include <linux/rtnetlink.h>
+#include <net/ieee80211_radiotap.h>
+
+#include <wlioctl.h>
+#include <bcmutils.h>
+#include <linux_osl.h>
+#include <dhd_dbg.h>
+#include <dngl_stats.h>
+#include <dhd.h>
+
+typedef enum monitor_states
+{
+ MONITOR_STATE_DEINIT = 0x0,
+ MONITOR_STATE_INIT = 0x1,
+ MONITOR_STATE_INTERFACE_ADDED = 0x2,
+ MONITOR_STATE_INTERFACE_DELETED = 0x4
+} monitor_states_t;
+extern int dhd_start_xmit(struct sk_buff *skb, struct net_device *net);
+
+/**
+ * Local declarations and defintions (not exposed)
+ */
+#define MON_PRINT(format, ...) printk("DHD-MON: %s " format, __func__, ##__VA_ARGS__)
+#define MON_TRACE MON_PRINT
+
+typedef struct monitor_interface {
+ int radiotap_enabled;
+ struct net_device* real_ndev; /* The real interface that the monitor is on */
+ struct net_device* mon_ndev;
+} monitor_interface;
+
+typedef struct dhd_linux_monitor {
+ void *dhd_pub;
+ monitor_states_t monitor_state;
+ monitor_interface mon_if[DHD_MAX_IFS];
+ struct mutex lock; /* lock to protect mon_if */
+} dhd_linux_monitor_t;
+
+static dhd_linux_monitor_t g_monitor;
+
+static struct net_device* lookup_real_netdev(char *name);
+static monitor_interface* ndev_to_monif(struct net_device *ndev);
+static int dhd_mon_if_open(struct net_device *ndev);
+static int dhd_mon_if_stop(struct net_device *ndev);
+static int dhd_mon_if_subif_start_xmit(struct sk_buff *skb, struct net_device *ndev);
+static void dhd_mon_if_set_multicast_list(struct net_device *ndev);
+static int dhd_mon_if_change_mac(struct net_device *ndev, void *addr);
+
+static const struct net_device_ops dhd_mon_if_ops = {
+ .ndo_open = dhd_mon_if_open,
+ .ndo_stop = dhd_mon_if_stop,
+ .ndo_start_xmit = dhd_mon_if_subif_start_xmit,
+ .ndo_set_multicast_list = dhd_mon_if_set_multicast_list,
+ .ndo_set_mac_address = dhd_mon_if_change_mac,
+};
+
+/**
+ * Local static function defintions
+ */
+
+/* Look up dhd's net device table to find a match (e.g. interface "eth0" is a match for "mon.eth0"
+ * "p2p-eth0-0" is a match for "mon.p2p-eth0-0")
+ */
+static struct net_device* lookup_real_netdev(char *name)
+{
+ int i;
+ int len = 0;
+ int last_name_len = 0;
+ struct net_device *ndev;
+ struct net_device *ndev_found = NULL;
+
+ /* We need to find interface "p2p-p2p-0" corresponding to monitor interface "mon-p2p-0",
+ * Once mon iface name reaches IFNAMSIZ, it is reset to p2p0-0 and corresponding mon
+ * iface would be mon-p2p0-0.
+ */
+ for (i = 0; i < DHD_MAX_IFS; i++) {
+ ndev = dhd_idx2net(g_monitor.dhd_pub, i);
+
+ /* Skip "p2p" and look for "-p2p0-x" in monitor interface name. If it
+ * it matches, then this netdev is the corresponding real_netdev.
+ */
+ if (ndev && strstr(ndev->name, "p2p-p2p0")) {
+ len = strlen("p2p");
+ } else {
+ /* if p2p- is not present, then the IFNAMSIZ have reached and name
+ * would have got reset. In this casse,look for p2p0-x in mon-p2p0-x
+ */
+ len = 0;
+ }
+ if (ndev && strstr(name, (ndev->name + len))) {
+ if (strlen(ndev->name) > last_name_len) {
+ ndev_found = ndev;
+ last_name_len = strlen(ndev->name);
+ }
+ }
+ }
+
+ return ndev_found;
+}
+
+static monitor_interface* ndev_to_monif(struct net_device *ndev)
+{
+ int i;
+
+ for (i = 0; i < DHD_MAX_IFS; i++) {
+ if (g_monitor.mon_if[i].mon_ndev == ndev)
+ return &g_monitor.mon_if[i];
+ }
+
+ return NULL;
+}
+
+static int dhd_mon_if_open(struct net_device *ndev)
+{
+ int ret = 0;
+
+ MON_PRINT("enter\n");
+ return ret;
+}
+
+static int dhd_mon_if_stop(struct net_device *ndev)
+{
+ int ret = 0;
+
+ MON_PRINT("enter\n");
+ return ret;
+}
+
+static int dhd_mon_if_subif_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ int ret = 0;
+ int rtap_len;
+ int qos_len = 0;
+ int dot11_hdr_len = 24;
+ int snap_len = 6;
+ unsigned char *pdata;
+ unsigned short frame_ctl;
+ unsigned char src_mac_addr[6];
+ unsigned char dst_mac_addr[6];
+ struct ieee80211_hdr *dot11_hdr;
+ struct ieee80211_radiotap_header *rtap_hdr;
+ monitor_interface* mon_if;
+
+ MON_PRINT("enter\n");
+
+ mon_if = ndev_to_monif(ndev);
+ if (mon_if == NULL || mon_if->real_ndev == NULL) {
+ MON_PRINT(" cannot find matched net dev, skip the packet\n");
+ goto fail;
+ }
+
+ if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header)))
+ goto fail;
+
+ rtap_hdr = (struct ieee80211_radiotap_header *)skb->data;
+ if (unlikely(rtap_hdr->it_version))
+ goto fail;
+
+ rtap_len = ieee80211_get_radiotap_len(skb->data);
+ if (unlikely(skb->len < rtap_len))
+ goto fail;
+
+ MON_PRINT("radiotap len (should be 14): %d\n", rtap_len);
+
+ /* Skip the ratio tap header */
+ skb_pull(skb, rtap_len);
+
+ dot11_hdr = (struct ieee80211_hdr *)skb->data;
+ frame_ctl = le16_to_cpu(dot11_hdr->frame_control);
+ /* Check if the QoS bit is set */
+ if ((frame_ctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) {
+ /* Check if this ia a Wireless Distribution System (WDS) frame
+ * which has 4 MAC addresses
+ */
+ if (dot11_hdr->frame_control & 0x0080)
+ qos_len = 2;
+ if ((dot11_hdr->frame_control & 0x0300) == 0x0300)
+ dot11_hdr_len += 6;
+
+ memcpy(dst_mac_addr, dot11_hdr->addr1, sizeof(dst_mac_addr));
+ memcpy(src_mac_addr, dot11_hdr->addr2, sizeof(src_mac_addr));
+
+ /* Skip the 802.11 header, QoS (if any) and SNAP, but leave spaces for
+ * for two MAC addresses
+ */
+ skb_pull(skb, dot11_hdr_len + qos_len + snap_len - sizeof(src_mac_addr) * 2);
+ pdata = (unsigned char*)skb->data;
+ memcpy(pdata, dst_mac_addr, sizeof(dst_mac_addr));
+ memcpy(pdata + sizeof(dst_mac_addr), src_mac_addr, sizeof(src_mac_addr));
+
+ MON_PRINT("if name: %s, matched if name %s\n", ndev->name, mon_if->real_ndev->name);
+
+ /* Use the real net device to transmit the packet */
+ ret = dhd_start_xmit(skb, mon_if->real_ndev);
+
+ return ret;
+ }
+fail:
+ dev_kfree_skb(skb);
+ return 0;
+}
+
+static void dhd_mon_if_set_multicast_list(struct net_device *ndev)
+{
+ monitor_interface* mon_if;
+
+ mon_if = ndev_to_monif(ndev);
+ if (mon_if == NULL || mon_if->real_ndev == NULL) {
+ MON_PRINT(" cannot find matched net dev, skip the packet\n");
+ } else {
+ MON_PRINT("enter, if name: %s, matched if name %s\n",
+ ndev->name, mon_if->real_ndev->name);
+ }
+}
+
+static int dhd_mon_if_change_mac(struct net_device *ndev, void *addr)
+{
+ int ret = 0;
+ monitor_interface* mon_if;
+
+ mon_if = ndev_to_monif(ndev);
+ if (mon_if == NULL || mon_if->real_ndev == NULL) {
+ MON_PRINT(" cannot find matched net dev, skip the packet\n");
+ } else {
+ MON_PRINT("enter, if name: %s, matched if name %s\n",
+ ndev->name, mon_if->real_ndev->name);
+ }
+ return ret;
+}
+
+/**
+ * Global function definitions (declared in dhd_linux_mon.h)
+ */
+
+int dhd_add_monitor(char *name, struct net_device **new_ndev)
+{
+ int i;
+ int idx = -1;
+ int ret = 0;
+ struct net_device* ndev = NULL;
+ dhd_linux_monitor_t **dhd_mon;
+
+ mutex_lock(&g_monitor.lock);
+
+ MON_TRACE("enter, if name: %s\n", name);
+ if (!name || !new_ndev) {
+ MON_PRINT("invalid parameters\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*
+ * Find a vacancy
+ */
+ for (i = 0; i < DHD_MAX_IFS; i++)
+ if (g_monitor.mon_if[i].mon_ndev == NULL) {
+ idx = i;
+ break;
+ }
+ if (idx == -1) {
+ MON_PRINT("exceeds maximum interfaces\n");
+ ret = -EFAULT;
+ goto out;
+ }
+
+ ndev = alloc_etherdev(sizeof(dhd_linux_monitor_t*));
+ if (!ndev) {
+ MON_PRINT("failed to allocate memory\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ndev->type = ARPHRD_IEEE80211_RADIOTAP;
+ strncpy(ndev->name, name, IFNAMSIZ);
+ ndev->name[IFNAMSIZ - 1] = 0;
+ ndev->netdev_ops = &dhd_mon_if_ops;
+
+ ret = register_netdevice(ndev);
+ if (ret) {
+ MON_PRINT(" register_netdevice failed (%d)\n", ret);
+ goto out;
+ }
+
+ *new_ndev = ndev;
+ g_monitor.mon_if[idx].radiotap_enabled = TRUE;
+ g_monitor.mon_if[idx].mon_ndev = ndev;
+ g_monitor.mon_if[idx].real_ndev = lookup_real_netdev(name);
+ dhd_mon = (dhd_linux_monitor_t **)netdev_priv(ndev);
+ *dhd_mon = &g_monitor;
+ g_monitor.monitor_state = MONITOR_STATE_INTERFACE_ADDED;
+ MON_PRINT("net device returned: 0x%p\n", ndev);
+ MON_PRINT("found a matched net device, name %s\n", g_monitor.mon_if[idx].real_ndev->name);
+
+out:
+ if (ret && ndev)
+ free_netdev(ndev);
+
+ mutex_unlock(&g_monitor.lock);
+ return ret;
+
+}
+
+int dhd_del_monitor(struct net_device *ndev)
+{
+ int i;
+ bool rollback_lock = false;
+ if (!ndev)
+ return -EINVAL;
+ mutex_lock(&g_monitor.lock);
+ for (i = 0; i < DHD_MAX_IFS; i++) {
+ if (g_monitor.mon_if[i].mon_ndev == ndev ||
+ g_monitor.mon_if[i].real_ndev == ndev) {
+ g_monitor.mon_if[i].real_ndev = NULL;
+ if (rtnl_is_locked()) {
+ rtnl_unlock();
+ rollback_lock = true;
+ }
+ unregister_netdev(g_monitor.mon_if[i].mon_ndev);
+ free_netdev(g_monitor.mon_if[i].mon_ndev);
+ g_monitor.mon_if[i].mon_ndev = NULL;
+ g_monitor.monitor_state = MONITOR_STATE_INTERFACE_DELETED;
+ break;
+ }
+ }
+ if (rollback_lock) {
+ rtnl_lock();
+ rollback_lock = false;
+ }
+
+ if (g_monitor.monitor_state !=
+ MONITOR_STATE_INTERFACE_DELETED)
+ MON_PRINT("interface not found in monitor IF array, is this a monitor IF? 0x%p\n",
+ ndev);
+ mutex_unlock(&g_monitor.lock);
+
+ return 0;
+}
+
+int dhd_monitor_init(void *dhd_pub)
+{
+ if (g_monitor.monitor_state == MONITOR_STATE_DEINIT) {
+ g_monitor.dhd_pub = dhd_pub;
+ mutex_init(&g_monitor.lock);
+ g_monitor.monitor_state = MONITOR_STATE_INIT;
+ }
+ return 0;
+}
+
+int dhd_monitor_uninit(void)
+{
+ int i;
+ struct net_device *ndev;
+ bool rollback_lock = false;
+ mutex_lock(&g_monitor.lock);
+ if (g_monitor.monitor_state != MONITOR_STATE_DEINIT) {
+ for (i = 0; i < DHD_MAX_IFS; i++) {
+ ndev = g_monitor.mon_if[i].mon_ndev;
+ if (ndev) {
+ if (rtnl_is_locked()) {
+ rtnl_unlock();
+ rollback_lock = true;
+ }
+ unregister_netdev(ndev);
+ free_netdev(ndev);
+ g_monitor.mon_if[i].real_ndev = NULL;
+ g_monitor.mon_if[i].mon_ndev = NULL;
+ if (rollback_lock) {
+ rtnl_lock();
+ rollback_lock = false;
+ }
+ }
+ }
+ g_monitor.monitor_state = MONITOR_STATE_DEINIT;
+ }
+ mutex_unlock(&g_monitor.lock);
+ return 0;
+}
diff --git a/drivers/net/wireless/bcmdhd/wldev_common.c b/drivers/net/wireless/bcmdhd/wldev_common.c
index bb3eaea90d0f..827033185035 100644
--- a/drivers/net/wireless/bcmdhd/wldev_common.c
+++ b/drivers/net/wireless/bcmdhd/wldev_common.c
@@ -24,12 +24,13 @@
* $Id: wldev_common.c,v 1.1.4.1.2.14 2011-02-09 01:40:07 $
*/
-#include <linux/module.h>
+#include <osl.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
#include <linux/netdevice.h>
#include <wldev_common.h>
#include <bcmutils.h>
-#include <dhd_dbg.h>
#define htod32(i) i
#define htod16(i) i
@@ -37,6 +38,13 @@
#define dtoh16(i) i
#define htodchanspec(i) i
#define dtohchanspec(i) i
+
+#define WLDEV_ERROR(args) \
+ do { \
+ printk(KERN_ERR "WLDEV-ERROR) %s : ", __func__); \
+ printk args; \
+ } while (0)
+
extern int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd);
s32 wldev_ioctl(
@@ -71,26 +79,34 @@ static s32 wldev_mkiovar(
s32 wldev_iovar_getbuf(
struct net_device *dev, s8 *iovar_name,
- void *param, s32 paramlen, void *buf, s32 buflen)
+ void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync)
{
s32 ret = 0;
s32 iovar_len = 0;
-
+ if (buf_sync) {
+ mutex_lock(buf_sync);
+ }
iovar_len = wldev_mkiovar(iovar_name, param, paramlen, buf, buflen);
ret = wldev_ioctl(dev, WLC_GET_VAR, buf, buflen, FALSE);
+ if (buf_sync)
+ mutex_unlock(buf_sync);
return ret;
}
s32 wldev_iovar_setbuf(
struct net_device *dev, s8 *iovar_name,
- void *param, s32 paramlen, void *buf, s32 buflen)
+ void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync)
{
s32 ret = 0;
s32 iovar_len;
-
+ if (buf_sync) {
+ mutex_lock(buf_sync);
+ }
iovar_len = wldev_mkiovar(iovar_name, param, paramlen, buf, buflen);
ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE);
+ if (buf_sync)
+ mutex_unlock(buf_sync);
return ret;
}
@@ -102,7 +118,7 @@ s32 wldev_iovar_setint(
val = htod32(val);
memset(iovar_buf, 0, sizeof(iovar_buf));
return wldev_iovar_setbuf(dev, iovar, &val, sizeof(val), iovar_buf,
- sizeof(iovar_buf));
+ sizeof(iovar_buf), NULL);
}
@@ -114,7 +130,7 @@ s32 wldev_iovar_getint(
memset(iovar_buf, 0, sizeof(iovar_buf));
err = wldev_iovar_getbuf(dev, iovar, pval, sizeof(*pval), iovar_buf,
- sizeof(iovar_buf));
+ sizeof(iovar_buf), NULL);
if (err == 0)
{
memcpy(pval, iovar_buf, sizeof(*pval));
@@ -148,7 +164,7 @@ s32 wldev_mkiovar_bsscfg(
if (buflen < 0 || iolen > (u32)buflen)
{
- DHD_ERROR(("%s: buffer is too short\n", __FUNCTION__));
+ WLDEV_ERROR(("%s: buffer is too short\n", __FUNCTION__));
return BCME_BUFTOOSHORT;
}
@@ -177,26 +193,37 @@ s32 wldev_mkiovar_bsscfg(
s32 wldev_iovar_getbuf_bsscfg(
struct net_device *dev, s8 *iovar_name,
- void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx)
+ void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync)
{
s32 ret = 0;
s32 iovar_len = 0;
-
+ if (buf_sync) {
+ mutex_lock(buf_sync);
+ }
iovar_len = wldev_mkiovar_bsscfg(iovar_name, param, paramlen, buf, buflen, bsscfg_idx);
ret = wldev_ioctl(dev, WLC_GET_VAR, buf, buflen, FALSE);
+ if (buf_sync) {
+ mutex_unlock(buf_sync);
+ }
return ret;
}
s32 wldev_iovar_setbuf_bsscfg(
struct net_device *dev, s8 *iovar_name,
- void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx)
+ void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync)
{
s32 ret = 0;
s32 iovar_len;
-
+ if (buf_sync) {
+ mutex_lock(buf_sync);
+ }
iovar_len = wldev_mkiovar_bsscfg(iovar_name, param, paramlen, buf, buflen, bsscfg_idx);
+
ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE);
+ if (buf_sync) {
+ mutex_unlock(buf_sync);
+ }
return ret;
}
@@ -208,7 +235,7 @@ s32 wldev_iovar_setint_bsscfg(
val = htod32(val);
memset(iovar_buf, 0, sizeof(iovar_buf));
return wldev_iovar_setbuf_bsscfg(dev, iovar, &val, sizeof(val), iovar_buf,
- sizeof(iovar_buf), bssidx);
+ sizeof(iovar_buf), bssidx, NULL);
}
@@ -220,7 +247,7 @@ s32 wldev_iovar_getint_bsscfg(
memset(iovar_buf, 0, sizeof(iovar_buf));
err = wldev_iovar_getbuf_bsscfg(dev, iovar, pval, sizeof(*pval), iovar_buf,
- sizeof(iovar_buf), bssidx);
+ sizeof(iovar_buf), bssidx, NULL);
if (err == 0)
{
memcpy(pval, iovar_buf, sizeof(*pval));
@@ -309,16 +336,16 @@ int wldev_set_country(
return error;
error = wldev_iovar_getbuf(dev, "country", &cspec, sizeof(cspec),
- smbuf, sizeof(smbuf));
+ smbuf, sizeof(smbuf), NULL);
if (error < 0)
- DHD_ERROR(("%s: get country failed = %d\n", __FUNCTION__, error));
+ WLDEV_ERROR(("%s: get country failed = %d\n", __FUNCTION__, error));
if ((error < 0) ||
(strncmp(country_code, smbuf, WLC_CNTRY_BUF_SZ) != 0)) {
bzero(&scbval, sizeof(scb_val_t));
error = wldev_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t), 1);
if (error < 0) {
- DHD_ERROR(("%s: set country failed due to Disassoc error %d\n",
+ WLDEV_ERROR(("%s: set country failed due to Disassoc error %d\n",
__FUNCTION__, error));
return error;
}
@@ -328,14 +355,64 @@ int wldev_set_country(
memcpy(cspec.ccode, country_code, WLC_CNTRY_BUF_SZ);
get_customized_country_code((char *)&cspec.country_abbrev, &cspec);
error = wldev_iovar_setbuf(dev, "country", &cspec, sizeof(cspec),
- smbuf, sizeof(smbuf));
+ smbuf, sizeof(smbuf), NULL);
if (error < 0) {
- DHD_ERROR(("%s: set country for %s as %s rev %d failed\n",
+ WLDEV_ERROR(("%s: set country for %s as %s rev %d failed\n",
__FUNCTION__, country_code, cspec.ccode, cspec.rev));
return error;
}
dhd_bus_country_set(dev, &cspec);
- DHD_INFO(("%s: set country for %s as %s rev %d\n",
+ WLDEV_ERROR(("%s: set country for %s as %s rev %d\n",
__FUNCTION__, country_code, cspec.ccode, cspec.rev));
return 0;
}
+
+/*
+ * softap channel autoselect
+ */
+int wldev_get_auto_channel(struct net_device *dev, int *chan)
+{
+ int chosen = 0;
+ wl_uint32_list_t request;
+ int retry = 0;
+ int updown = 0;
+ int ret = 0;
+ wlc_ssid_t null_ssid;
+
+ memset(&null_ssid, 0, sizeof(wlc_ssid_t));
+ ret |= wldev_ioctl(dev, WLC_UP, &updown, sizeof(updown), true);
+
+ ret |= wldev_ioctl(dev, WLC_SET_SSID, &null_ssid, sizeof(null_ssid), true);
+
+ request.count = htod32(0);
+ ret = wldev_ioctl(dev, WLC_START_CHANNEL_SEL, &request, sizeof(request), true);
+ if (ret < 0) {
+ WLDEV_ERROR(("can't start auto channel scan:%d\n", ret));
+ goto fail;
+ }
+
+ while (retry++ < 15) {
+
+ bcm_mdelay(350);
+
+ ret = wldev_ioctl(dev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen), false);
+
+ if ((ret == 0) && (dtoh32(chosen) != 0)) {
+ *chan = (uint16)chosen & 0x00FF; /* covert chanspec --> chan number */
+ printf("%s: Got channel = %d, attempt:%d\n",
+ __FUNCTION__, *chan, retry);
+ break;
+ }
+ }
+
+ if ((ret = wldev_ioctl(dev, WLC_DOWN, &updown, sizeof(updown), true)) < 0) {
+ WLDEV_ERROR(("%s fail to WLC_DOWN ioctl err =%d\n", __FUNCTION__, ret));
+ goto fail;
+ }
+
+fail :
+ if (ret < 0) {
+ WLDEV_ERROR(("%s: return value %d\n", __FUNCTION__, ret));
+ }
+ return ret;
+}
diff --git a/drivers/net/wireless/bcmdhd/wldev_common.h b/drivers/net/wireless/bcmdhd/wldev_common.h
index 46326803e216..f58660944420 100644
--- a/drivers/net/wireless/bcmdhd/wldev_common.h
+++ b/drivers/net/wireless/bcmdhd/wldev_common.h
@@ -21,33 +21,33 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: wldev_common.h,v 1.1.4.1.2.14 2011-02-09 01:40:07 Exp $
+ * $Id: wldev_common.h,v 1.1.4.1.2.14 2011-02-09 01:40:07 $
*/
#ifndef __WLDEV_COMMON_H__
#define __WLDEV_COMMON_H__
#include <wlioctl.h>
-/** wl_dev_ioctl - get/set IOCTLs, will call net_device's do_ioctl (or
+/* wl_dev_ioctl - get/set IOCTLs, will call net_device's do_ioctl (or
* netdev_ops->ndo_do_ioctl in new kernels)
* @dev: the net_device handle
*/
s32 wldev_ioctl(
struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set);
-/** Retrieve named IOVARs, this function calls wl_dev_ioctl with
+/** Retrieve named IOVARs, this function calls wl_dev_ioctl with
* WLC_GET_VAR IOCTL code
*/
s32 wldev_iovar_getbuf(
struct net_device *dev, s8 *iovar_name,
- void *param, s32 paramlen, void *buf, s32 buflen);
+ void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync);
/** Set named IOVARs, this function calls wl_dev_ioctl with
* WLC_SET_VAR IOCTL code
*/
s32 wldev_iovar_setbuf(
struct net_device *dev, s8 *iovar_name,
- void *param, s32 paramlen, void *buf, s32 buflen);
+ void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync);
s32 wldev_iovar_setint(
struct net_device *dev, s8 *iovar, s32 val);
@@ -67,15 +67,15 @@ s32 wldev_mkiovar_bsscfg(
* WLC_GET_VAR IOCTL code
*/
s32 wldev_iovar_getbuf_bsscfg(
- struct net_device *dev, s8 *iovar_name,
- void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx);
+ struct net_device *dev, s8 *iovar_name, void *param, s32 paramlen,
+ void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync);
/** Set named and bsscfg indexed IOVARs, this function calls wl_dev_ioctl with
* WLC_SET_VAR IOCTL code
*/
s32 wldev_iovar_setbuf_bsscfg(
- struct net_device *dev, s8 *iovar_name,
- void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx);
+ struct net_device *dev, s8 *iovar_name, void *param, s32 paramlen,
+ void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync);
s32 wldev_iovar_getint_bsscfg(
struct net_device *dev, s8 *iovar, s32 *pval, s32 bssidx);
@@ -92,9 +92,9 @@ extern int net_os_wake_lock_timeout(struct net_device *dev);
extern int net_os_wake_lock_timeout_enable(struct net_device *dev, int val);
extern int net_os_set_dtim_skip(struct net_device *dev, int val);
extern int net_os_set_suspend_disable(struct net_device *dev, int val);
-extern int net_os_set_suspend(struct net_device *dev, int val);
+extern int net_os_set_suspend(struct net_device *dev, int val, int force);
extern int wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_t* ssid,
- int max, int *bytes_left);
+ int max, int *bytes_left);
/* Get the link speed from dongle, speed is in kpbs */
int wldev_get_link_speed(struct net_device *dev, int *plink_speed);
@@ -107,4 +107,6 @@ int wldev_get_band(struct net_device *dev, uint *pband);
int wldev_set_band(struct net_device *dev, uint band);
+int wldev_get_auto_channel(struct net_device *dev, int *chan);
+
#endif /* __WLDEV_COMMON_H__ */
diff --git a/drivers/net/wireless/sd8797/Makefile b/drivers/net/wireless/sd8797/Makefile
index d5eb7872a232..3ef70380dd82 100644
--- a/drivers/net/wireless/sd8797/Makefile
+++ b/drivers/net/wireless/sd8797/Makefile
@@ -52,6 +52,7 @@ EXTRA_CFLAGS += -DPROC_DEBUG
EXTRA_CFLAGS += -DSDIO_MULTI_PORT_TX_AGGR
EXTRA_CFLAGS += -DSDIO_MULTI_PORT_RX_AGGR
EXTRA_CFLAGS += -DSDIO_SUSPEND_RESUME
+EXTRA_CFLAGS += -DMMC_PM_KEEP_POWER
EXTRA_CFLAGS += -DDFS_TESTING_SUPPORT
EXTRA_CFLAGS += -DMFG_CMD_SUPPORT
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_11d.c b/drivers/net/wireless/sd8797/mlan/mlan_11d.c
index 1727c5890fc8..fdc0d993e381 100644
--- a/drivers/net/wireless/sd8797/mlan/mlan_11d.c
+++ b/drivers/net/wireless/sd8797/mlan/mlan_11d.c
@@ -2,7 +2,7 @@
*
* @brief This file contains functions for 802.11D.
*
- * Copyright (C) 2008-2011, Marvell International Ltd.
+ * Copyright (C) 2008-2012, Marvell International Ltd.
*
* This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
@@ -55,6 +55,7 @@ static region_code_mapping_t region_code_mapping[] = {
{"JP ", 0x40}, /* Japan */
{"JP ", 0x41}, /* Japan */
{"CN ", 0x50}, /* China */
+ {"JP ", 0xFE}, /* Japan */
{"JP ", 0xFF}, /* Japan special */
};
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_11h.c b/drivers/net/wireless/sd8797/mlan/mlan_11h.c
index 7e08f4cd5d8a..3a38979a8dd2 100644
--- a/drivers/net/wireless/sd8797/mlan/mlan_11h.c
+++ b/drivers/net/wireless/sd8797/mlan/mlan_11h.c
@@ -2,7 +2,7 @@
*
* @brief This file contains functions for 802.11H.
*
- * Copyright (C) 2008-2011, Marvell International Ltd.
+ * Copyright (C) 2008-2012, Marvell International Ltd.
*
* This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
@@ -298,6 +298,11 @@ wlan_11h_set_supp_channels_ie(mlan_private * priv,
sizeof(IEEEtypes_SupportedChannels_t));
cfp_bg = cfp_a = priv->adapter->region_code;
+ if (!priv->adapter->region_code) {
+ /* Invalid region code, use CFP code */
+ cfp_bg = priv->adapter->cfp_code_bg;
+ cfp_a = priv->adapter->cfp_code_a;
+ }
if ((band & BAND_B) || (band & BAND_G)) {
/*
@@ -355,6 +360,23 @@ wlan_11h_set_supp_channels_ie(mlan_private * priv,
psup_chan->subband[num_subbands++] = wlan_11h_unii_middle_band;
psup_chan->subband[num_subbands++] = wlan_11h_unii_mid_upper_band;
break;
+ case 0x1: /* Low band (5150-5250 MHz) channels */
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_lower_band;
+ break;
+ case 0x2: /* Lower middle band (5250-5350 MHz) channels */
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_middle_band;
+ break;
+ case 0x3: /* Upper middle band (5470-5725 MHz) channels */
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_mid_upper_band;
+ break;
+ case 0x4: /* High band (5725-5850 MHz) channels */
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_upper_band;
+ break;
+ case 0x5: /* Low band (5150-5250 MHz) and High band
+ (5725-5850 MHz) channels */
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_lower_band;
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_upper_band;
+ break;
}
}
@@ -1799,9 +1821,15 @@ wlan_11h_radar_detect_required(mlan_private * priv, t_u8 channel)
required = wlan_get_cfp_radar_detect(priv, channel);
- PRINTM(MINFO, "11h: Radar detection in region %#02x "
- "is %srequired for channel %d\n",
- priv->adapter->region_code, (required ? "" : "not "), channel);
+ if (!priv->adapter->region_code)
+ PRINTM(MINFO, "11h: Radar detection in CFP code[BG:%#x, A:%#x] "
+ "is %srequired for channel %d\n",
+ priv->adapter->cfp_code_bg, priv->adapter->cfp_code_a,
+ (required ? "" : "not "), channel);
+ else
+ PRINTM(MINFO, "11h: Radar detection in region %#02x "
+ "is %srequired for channel %d\n",
+ priv->adapter->region_code, (required ? "" : "not "), channel);
if (required == MTRUE && priv->media_connected == MTRUE
&& priv->curr_bss_params.bss_descriptor.channel == channel) {
@@ -3153,13 +3181,13 @@ wlan_11h_switch_non_dfs_chan(mlan_private * priv, t_u8 * chan)
def_chan = (t_u8) chn_tbl->pcfp[rand_entry].channel;
rand_tries++;
} while ((wlan_11h_is_channel_under_nop(pmadapter, def_chan) ||
- chn_tbl->pcfp[rand_entry].radar_detect == MTRUE) &&
- (rand_tries < MAX_SWITCH_CHANNEL_RETRIES));
+ chn_tbl->pcfp[rand_entry].passive_scan_or_radar_detect == MTRUE)
+ && (rand_tries < MAX_SWITCH_CHANNEL_RETRIES));
/* meet max retries, use the lowest non-dfs channel */
if (rand_tries == MAX_SWITCH_CHANNEL_RETRIES) {
for (i = 0; i < chn_tbl->num_cfp; i++) {
- if (chn_tbl->pcfp[i].radar_detect == MFALSE &&
+ if (chn_tbl->pcfp[i].passive_scan_or_radar_detect == MFALSE &&
!wlan_11h_is_channel_under_nop(pmadapter,
(t_u8) chn_tbl->pcfp[i].
channel)) {
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_11n.c b/drivers/net/wireless/sd8797/mlan/mlan_11n.c
index 48b51a5bf7e0..5e78748e4a3b 100644
--- a/drivers/net/wireless/sd8797/mlan/mlan_11n.c
+++ b/drivers/net/wireless/sd8797/mlan/mlan_11n.c
@@ -1335,6 +1335,7 @@ wlan_ret_tx_bf_cfg(IN pmlan_private pmpriv,
}
#ifdef STA_SUPPORT
+
/**
* @brief This function append the 802_11N tlv
*
@@ -1426,12 +1427,12 @@ wlan_cmd_append_11n_tlv(IN mlan_private * pmpriv,
pbss_desc->pht_info->ht_info.pri_chan;
pchan_list->chan_scan_param[0].radio_type =
wlan_band_to_radio_type((t_u8) pbss_desc->bss_band);
-
if (ISSUPP_CHANWIDTH40(usr_dot_11n_dev_cap) &&
- ISALLOWED_CHANWIDTH40(pbss_desc->pht_info->ht_info.field2))
+ ISALLOWED_CHANWIDTH40(pbss_desc->pht_info->ht_info.field2)) {
SET_SECONDARYCHAN(pchan_list->chan_scan_param[0].radio_type,
GET_SECONDARYCHAN(pbss_desc->pht_info->ht_info.
field2));
+ }
HEXDUMP("ChanList", (t_u8 *) pchan_list,
sizeof(MrvlIEtypes_ChanListParamSet_t));
@@ -1467,15 +1468,13 @@ wlan_cmd_append_11n_tlv(IN mlan_private * pmpriv,
memcpy(pmadapter, (t_u8 *) pext_cap + sizeof(MrvlIEtypesHeader_t),
(t_u8 *) pbss_desc->pext_cap + sizeof(IEEEtypes_Header_t),
- pext_cap->header.len);
-
+ pbss_desc->pext_cap->ieee_hdr.len);
HEXDUMP("Extended Capabilities IE", (t_u8 *) pext_cap,
sizeof(MrvlIETypes_ExtCap_t));
*ppbuffer += sizeof(MrvlIETypes_ExtCap_t);
ret_len += sizeof(MrvlIETypes_ExtCap_t);
pext_cap->header.len = wlan_cpu_to_le16(pext_cap->header.len);
}
-
LEAVE();
return ret_len;
}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_11n_aggr.c b/drivers/net/wireless/sd8797/mlan/mlan_11n_aggr.c
index 6af4b6a698e8..6125262d5b7a 100644
--- a/drivers/net/wireless/sd8797/mlan/mlan_11n_aggr.c
+++ b/drivers/net/wireless/sd8797/mlan/mlan_11n_aggr.c
@@ -333,7 +333,9 @@ wlan_11n_aggregate_pkt(mlan_private * priv, raListTbl * pra_list,
t_u8 *data;
int pad = 0;
mlan_status ret = MLAN_STATUS_SUCCESS;
+#ifdef DEBUG_LEVEL1
t_u32 sec, usec;
+#endif
mlan_tx_param tx_param;
#ifdef STA_SUPPORT
TxPD *ptx_pd = MNULL;
@@ -497,8 +499,7 @@ wlan_11n_aggregate_pkt(mlan_private * priv, raListTbl * pra_list,
pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
priv->wmm.ra_list_spinlock);
}
- pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle, &sec,
- &usec);
+ PRINTM_GET_SYS_TIME(MDATA, &sec, &usec);
PRINTM_NETINTF(MDATA, priv);
PRINTM(MDATA, "%lu.%06lu : Data => FW\n", sec, usec);
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_11n_rxreorder.c b/drivers/net/wireless/sd8797/mlan/mlan_11n_rxreorder.c
index 870081799c07..af689b7bab49 100644
--- a/drivers/net/wireless/sd8797/mlan/mlan_11n_rxreorder.c
+++ b/drivers/net/wireless/sd8797/mlan/mlan_11n_rxreorder.c
@@ -4,7 +4,7 @@
* driver.
*
* Copyright (C) 2008-2011, Marvell International Ltd.
- *
+ *
* This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
* (the "License"). You may use, redistribute and/or modify this File in
@@ -639,6 +639,9 @@ wlan_cmd_11n_addba_rspgen(mlan_private * priv,
BLOCKACKPARAM_WINSIZE_POS);
win_size = (padd_ba_rsp->block_ack_param_set & BLOCKACKPARAM_WINSIZE_MASK)
>> BLOCKACKPARAM_WINSIZE_POS;
+ if (win_size == 0)
+ padd_ba_rsp->status_code = wlan_cpu_to_le16(ADDBA_RSP_STATUS_DECLINED);
+
padd_ba_rsp->block_ack_param_set =
wlan_cpu_to_le16(padd_ba_rsp->block_ack_param_set);
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_cfp.c b/drivers/net/wireless/sd8797/mlan/mlan_cfp.c
index 23e849f04b63..ccbb5aa1f666 100644
--- a/drivers/net/wireless/sd8797/mlan/mlan_cfp.c
+++ b/drivers/net/wireless/sd8797/mlan/mlan_cfp.c
@@ -4,7 +4,7 @@
* @brief This file contains WLAN client mode channel, frequency and power
* related code
*
- * Copyright (C) 2009-2011, Marvell International Ltd.
+ * Copyright (C) 2009-2012, Marvell International Ltd.
*
* This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
@@ -52,6 +52,30 @@ Change Log:
/** 2000mW */
#define WLAN_TX_PWR_CN_2000MW 33
+/** Region code mapping */
+typedef struct _country_code_mapping
+{
+ /** Region */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ /** Code for B/G CFP table */
+ t_u8 cfp_code_bg;
+ /** Code for A CFP table */
+ t_u8 cfp_code_a;
+} country_code_mapping_t;
+
+/** Region code mapping table */
+static country_code_mapping_t country_code_mapping[] = {
+ {"US", 0x10, 0x10}, /* US FCC */
+ {"CA", 0x10, 0x20}, /* IC Canada */
+ {"SG", 0x10, 0x10}, /* Singapore */
+ {"EU", 0x30, 0x30}, /* ETSI */
+ {"AU", 0x30, 0x30}, /* Australia */
+ {"KR", 0x30, 0x30}, /* Republic Of Korea */
+ {"FR", 0x32, 0x32}, /* France */
+ {"JP", 0xFF, 0x40}, /* Japan */
+ {"CN", 0x30, 0x50}, /* China */
+};
+
/**
* The structure for Channel-Frequency-Power table
*/
@@ -68,91 +92,108 @@ typedef struct _cfp_table
/* Format { Channel, Frequency (MHz), MaxTxPower } */
/** Band: 'B/G', Region: USA FCC/Canada IC */
static chan_freq_power_t channel_freq_power_US_BG[] = {
- {1, 2412, WLAN_TX_PWR_US_DEFAULT},
- {2, 2417, WLAN_TX_PWR_US_DEFAULT},
- {3, 2422, WLAN_TX_PWR_US_DEFAULT},
- {4, 2427, WLAN_TX_PWR_US_DEFAULT},
- {5, 2432, WLAN_TX_PWR_US_DEFAULT},
- {6, 2437, WLAN_TX_PWR_US_DEFAULT},
- {7, 2442, WLAN_TX_PWR_US_DEFAULT},
- {8, 2447, WLAN_TX_PWR_US_DEFAULT},
- {9, 2452, WLAN_TX_PWR_US_DEFAULT},
- {10, 2457, WLAN_TX_PWR_US_DEFAULT},
- {11, 2462, WLAN_TX_PWR_US_DEFAULT}
+ {1, 2412, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {2, 2417, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {3, 2422, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {4, 2427, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {5, 2432, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {6, 2437, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {7, 2442, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {8, 2447, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {9, 2452, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {10, 2457, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {11, 2462, WLAN_TX_PWR_US_DEFAULT, MFALSE}
};
/** Band: 'B/G', Region: Europe ETSI/China */
static chan_freq_power_t channel_freq_power_EU_BG[] = {
- {1, 2412, WLAN_TX_PWR_EMEA_DEFAULT},
- {2, 2417, WLAN_TX_PWR_EMEA_DEFAULT},
- {3, 2422, WLAN_TX_PWR_EMEA_DEFAULT},
- {4, 2427, WLAN_TX_PWR_EMEA_DEFAULT},
- {5, 2432, WLAN_TX_PWR_EMEA_DEFAULT},
- {6, 2437, WLAN_TX_PWR_EMEA_DEFAULT},
- {7, 2442, WLAN_TX_PWR_EMEA_DEFAULT},
- {8, 2447, WLAN_TX_PWR_EMEA_DEFAULT},
- {9, 2452, WLAN_TX_PWR_EMEA_DEFAULT},
- {10, 2457, WLAN_TX_PWR_EMEA_DEFAULT},
- {11, 2462, WLAN_TX_PWR_EMEA_DEFAULT},
- {12, 2467, WLAN_TX_PWR_EMEA_DEFAULT},
- {13, 2472, WLAN_TX_PWR_EMEA_DEFAULT}
+ {1, 2412, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {2, 2417, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {3, 2422, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {4, 2427, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {5, 2432, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {6, 2437, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {7, 2442, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {8, 2447, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {9, 2452, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {10, 2457, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {11, 2462, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {12, 2467, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {13, 2472, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE}
};
/** Band: 'B/G', Region: France */
static chan_freq_power_t channel_freq_power_FR_BG[] = {
- {1, 2412, WLAN_TX_PWR_FR_100MW},
- {2, 2417, WLAN_TX_PWR_FR_100MW},
- {3, 2422, WLAN_TX_PWR_FR_100MW},
- {4, 2427, WLAN_TX_PWR_FR_100MW},
- {5, 2432, WLAN_TX_PWR_FR_100MW},
- {6, 2437, WLAN_TX_PWR_FR_100MW},
- {7, 2442, WLAN_TX_PWR_FR_100MW},
- {8, 2447, WLAN_TX_PWR_FR_100MW},
- {9, 2452, WLAN_TX_PWR_FR_100MW},
- {10, 2457, WLAN_TX_PWR_FR_10MW},
- {11, 2462, WLAN_TX_PWR_FR_10MW},
- {12, 2467, WLAN_TX_PWR_FR_10MW},
- {13, 2472, WLAN_TX_PWR_FR_10MW}
+ {1, 2412, WLAN_TX_PWR_FR_100MW, MFALSE},
+ {2, 2417, WLAN_TX_PWR_FR_100MW, MFALSE},
+ {3, 2422, WLAN_TX_PWR_FR_100MW, MFALSE},
+ {4, 2427, WLAN_TX_PWR_FR_100MW, MFALSE},
+ {5, 2432, WLAN_TX_PWR_FR_100MW, MFALSE},
+ {6, 2437, WLAN_TX_PWR_FR_100MW, MFALSE},
+ {7, 2442, WLAN_TX_PWR_FR_100MW, MFALSE},
+ {8, 2447, WLAN_TX_PWR_FR_100MW, MFALSE},
+ {9, 2452, WLAN_TX_PWR_FR_100MW, MFALSE},
+ {10, 2457, WLAN_TX_PWR_FR_10MW, MFALSE},
+ {11, 2462, WLAN_TX_PWR_FR_10MW, MFALSE},
+ {12, 2467, WLAN_TX_PWR_FR_10MW, MFALSE},
+ {13, 2472, WLAN_TX_PWR_FR_10MW, MFALSE}
};
/** Band: 'B/G', Region: Japan */
static chan_freq_power_t channel_freq_power_JPN41_BG[] = {
- {1, 2412, WLAN_TX_PWR_JP_BG_DEFAULT},
- {2, 2417, WLAN_TX_PWR_JP_BG_DEFAULT},
- {3, 2422, WLAN_TX_PWR_JP_BG_DEFAULT},
- {4, 2427, WLAN_TX_PWR_JP_BG_DEFAULT},
- {5, 2432, WLAN_TX_PWR_JP_BG_DEFAULT},
- {6, 2437, WLAN_TX_PWR_JP_BG_DEFAULT},
- {7, 2442, WLAN_TX_PWR_JP_BG_DEFAULT},
- {8, 2447, WLAN_TX_PWR_JP_BG_DEFAULT},
- {9, 2452, WLAN_TX_PWR_JP_BG_DEFAULT},
- {10, 2457, WLAN_TX_PWR_JP_BG_DEFAULT},
- {11, 2462, WLAN_TX_PWR_JP_BG_DEFAULT},
- {12, 2467, WLAN_TX_PWR_JP_BG_DEFAULT},
- {13, 2472, WLAN_TX_PWR_JP_BG_DEFAULT}
+ {1, 2412, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {2, 2417, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {3, 2422, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {4, 2427, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {5, 2432, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {6, 2437, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {7, 2442, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {8, 2447, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {9, 2452, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {10, 2457, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {11, 2462, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {12, 2467, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {13, 2472, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE}
};
/** Band: 'B/G', Region: Japan */
static chan_freq_power_t channel_freq_power_JPN40_BG[] = {
- {14, 2484, WLAN_TX_PWR_JP_BG_DEFAULT}
+ {14, 2484, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE}
+};
+
+/** Band: 'B/G', Region: Japan */
+static chan_freq_power_t channel_freq_power_JPNFE_BG[] = {
+ {1, 2412, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {2, 2417, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {3, 2422, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {4, 2427, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {5, 2432, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {6, 2437, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {7, 2442, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {8, 2447, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {9, 2452, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {10, 2457, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {11, 2462, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {12, 2467, WLAN_TX_PWR_JP_BG_DEFAULT, MTRUE},
+ {13, 2472, WLAN_TX_PWR_JP_BG_DEFAULT, MTRUE}
};
/** Band : 'B/G', Region: Special */
static chan_freq_power_t channel_freq_power_SPECIAL_BG[] = {
- {1, 2412, WLAN_TX_PWR_JP_BG_DEFAULT},
- {2, 2417, WLAN_TX_PWR_JP_BG_DEFAULT},
- {3, 2422, WLAN_TX_PWR_JP_BG_DEFAULT},
- {4, 2427, WLAN_TX_PWR_JP_BG_DEFAULT},
- {5, 2432, WLAN_TX_PWR_JP_BG_DEFAULT},
- {6, 2437, WLAN_TX_PWR_JP_BG_DEFAULT},
- {7, 2442, WLAN_TX_PWR_JP_BG_DEFAULT},
- {8, 2447, WLAN_TX_PWR_JP_BG_DEFAULT},
- {9, 2452, WLAN_TX_PWR_JP_BG_DEFAULT},
- {10, 2457, WLAN_TX_PWR_JP_BG_DEFAULT},
- {11, 2462, WLAN_TX_PWR_JP_BG_DEFAULT},
- {12, 2467, WLAN_TX_PWR_JP_BG_DEFAULT},
- {13, 2472, WLAN_TX_PWR_JP_BG_DEFAULT},
- {14, 2484, WLAN_TX_PWR_JP_BG_DEFAULT}
+ {1, 2412, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {2, 2417, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {3, 2422, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {4, 2427, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {5, 2432, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {6, 2437, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {7, 2442, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {8, 2447, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {9, 2452, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {10, 2457, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {11, 2462, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {12, 2467, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {13, 2472, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {14, 2484, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE}
};
/**
@@ -194,6 +235,12 @@ static cfp_table_t cfp_table_BG[] = {
sizeof(channel_freq_power_EU_BG) / sizeof(chan_freq_power_t),
}
,
+ {
+ 0xfe, /* JAPAN */
+ channel_freq_power_JPNFE_BG,
+ sizeof(channel_freq_power_JPNFE_BG) / sizeof(chan_freq_power_t),
+ }
+ ,
{0xff, /* Special */
channel_freq_power_SPECIAL_BG,
sizeof(channel_freq_power_SPECIAL_BG) / sizeof(chan_freq_power_t),
@@ -317,6 +364,64 @@ static chan_freq_power_t channel_freq_power_CN_A[] = {
{165, 5825, WLAN_TX_PWR_CN_2000MW, MFALSE}
};
+/** Band: 'A', NULL */
+static chan_freq_power_t channel_freq_power_NULL_A[] = {
+};
+
+/** Band: 'A', Code: 1, Low band (5150-5250 MHz) channels */
+static chan_freq_power_t channel_freq_power_low_band[] = {
+ {36, 5180, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {40, 5200, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {44, 5220, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {48, 5240, WLAN_TX_PWR_DEFAULT, MFALSE},
+};
+
+/** Band: 'A', Code: 2, Lower middle band (5250-5350 MHz) channels */
+static chan_freq_power_t channel_freq_power_lower_middle_band[] = {
+ {52, 5260, WLAN_TX_PWR_DEFAULT, MTRUE},
+ {56, 5280, WLAN_TX_PWR_DEFAULT, MTRUE},
+ {60, 5300, WLAN_TX_PWR_DEFAULT, MTRUE},
+ {64, 5320, WLAN_TX_PWR_DEFAULT, MTRUE},
+};
+
+/** Band: 'A', Code: 3, Upper middle band (5470-5725 MHz) channels */
+static chan_freq_power_t channel_freq_power_upper_middle_band[] = {
+ {100, 5500, WLAN_TX_PWR_DEFAULT, MTRUE},
+ {104, 5520, WLAN_TX_PWR_DEFAULT, MTRUE},
+ {108, 5540, WLAN_TX_PWR_DEFAULT, MTRUE},
+ {112, 5560, WLAN_TX_PWR_DEFAULT, MTRUE},
+ {116, 5580, WLAN_TX_PWR_DEFAULT, MTRUE},
+ {120, 5600, WLAN_TX_PWR_DEFAULT, MTRUE},
+ {124, 5620, WLAN_TX_PWR_DEFAULT, MTRUE},
+ {128, 5640, WLAN_TX_PWR_DEFAULT, MTRUE},
+ {132, 5660, WLAN_TX_PWR_DEFAULT, MTRUE},
+ {136, 5680, WLAN_TX_PWR_DEFAULT, MTRUE},
+ {140, 5700, WLAN_TX_PWR_DEFAULT, MTRUE},
+};
+
+/** Band: 'A', Code: 4, High band (5725-5850 MHz) channels */
+static chan_freq_power_t channel_freq_power_high_band[] = {
+ {149, 5745, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {153, 5765, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {157, 5785, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {161, 5805, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {165, 5825, WLAN_TX_PWR_DEFAULT, MFALSE}
+};
+
+/** Band: 'A', Code: 5, Low band (5150-5250 MHz) and
+ * High band (5725-5850 MHz) channels */
+static chan_freq_power_t channel_freq_power_low_high_band[] = {
+ {36, 5180, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {40, 5200, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {44, 5220, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {48, 5240, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {149, 5745, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {153, 5765, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {157, 5785, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {161, 5805, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {165, 5825, WLAN_TX_PWR_DEFAULT, MFALSE}
+};
+
/**
* The 5GHz CFP tables
*/
@@ -356,11 +461,42 @@ static cfp_table_t cfp_table_A[] = {
sizeof(channel_freq_power_CN_A) / sizeof(chan_freq_power_t),
}
,
+ {0xfe, /* JAPAN */
+ channel_freq_power_NULL_A,
+ sizeof(channel_freq_power_NULL_A) / sizeof(chan_freq_power_t),
+ }
+ ,
{0xff, /* Special */
channel_freq_power_JPN_A,
sizeof(channel_freq_power_JPN_A) / sizeof(chan_freq_power_t),
}
,
+ {0x1, /* Low band (5150-5250 MHz) channels */
+ channel_freq_power_low_band,
+ sizeof(channel_freq_power_low_band) / sizeof(chan_freq_power_t)
+ }
+ ,
+ {0x2, /* Lower middle band (5250-5350 MHz) channels */
+ channel_freq_power_lower_middle_band,
+ sizeof(channel_freq_power_lower_middle_band) / sizeof(chan_freq_power_t)
+ }
+ ,
+ {0x3, /* Upper middle band (5470-5725 MHz) channels */
+ channel_freq_power_upper_middle_band,
+ sizeof(channel_freq_power_upper_middle_band) / sizeof(chan_freq_power_t)
+ }
+ ,
+ {0x4, /* High band (5725-5850 MHz) channels */
+ channel_freq_power_high_band,
+ sizeof(channel_freq_power_high_band) / sizeof(chan_freq_power_t)
+ }
+ ,
+ {0x5, /* Low band (5150-5250 MHz) and High band
+ (5725-5850 MHz) channels */
+ channel_freq_power_low_high_band,
+ sizeof(channel_freq_power_low_high_band) / sizeof(chan_freq_power_t)
+ }
+ ,
/* Add new region here */
};
@@ -374,7 +510,13 @@ static cfp_table_t cfp_table_A[] = {
* The table to keep region code
*/
t_u16 region_code_index[MRVDRV_MAX_REGION_CODE] =
- { 0x10, 0x20, 0x30, 0x32, 0x40, 0x41, 0x50, 0xff };
+ { 0x10, 0x20, 0x30, 0x32, 0x40, 0x41, 0x50, 0xfe, 0xff };
+
+/** The table to keep CFP code for BG */
+t_u16 cfp_code_index_bg[MRVDRV_MAX_CFP_CODE_BG] = { };
+
+/** The table to keep CFP code for A */
+t_u16 cfp_code_index_a[MRVDRV_MAX_CFP_CODE_A] = { 0x1, 0x2, 0x3, 0x4, 0x5 };
/**
* The rates supported for ad-hoc B mode
@@ -494,6 +636,11 @@ wlan_get_region_cfp_table(pmlan_adapter pmadapter, t_u8 region, t_u8 band,
ENTER();
cfp_bg = cfp_a = region;
+ if (!region) {
+ /* Invalid region code, use CFP code */
+ cfp_bg = pmadapter->cfp_code_bg;
+ cfp_a = pmadapter->cfp_code_a;
+ }
if (band & (BAND_B | BAND_G | BAND_GN)) {
for (i = 0; i < MLAN_CFP_TABLE_SIZE_BG; i++) {
@@ -521,7 +668,11 @@ wlan_get_region_cfp_table(pmlan_adapter pmadapter, t_u8 region, t_u8 band,
}
}
- PRINTM(MERROR, "Error Band[0x%x] or region[%#x]\n", band, region);
+ if (!region)
+ PRINTM(MERROR, "Error Band[0x%x] or code[BG:%#x, A:%#x]\n",
+ band, cfp_bg, cfp_a);
+ else
+ PRINTM(MERROR, "Error Band[0x%x] or region[%#x]\n", band, region);
LEAVE();
return MNULL;
@@ -530,6 +681,38 @@ wlan_get_region_cfp_table(pmlan_adapter pmadapter, t_u8 region, t_u8 band,
/********************************************************
Global Functions
********************************************************/
+/**
+ * @brief This function converts region string to integer code
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param country_code Country string
+ * @param cfp_bg Pointer to buffer
+ * @param cfp_a Pointer to buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_misc_country_2_cfp_table_code(pmlan_adapter pmadapter, t_u8 * country_code,
+ t_u8 * cfp_bg, t_u8 * cfp_a)
+{
+ t_u8 i;
+
+ ENTER();
+
+ /* Look for code in mapping table */
+ for (i = 0; i < NELEMENTS(country_code_mapping); i++) {
+ if (!memcmp(pmadapter, country_code_mapping[i].country_code,
+ country_code, COUNTRY_CODE_LEN - 1)) {
+ *cfp_bg = country_code_mapping[i].cfp_code_bg;
+ *cfp_a = country_code_mapping[i].cfp_code_a;
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+}
#ifdef STA_SUPPORT
#endif /* STA_SUPPORT */
@@ -1137,7 +1320,7 @@ wlan_get_cfp_radar_detect(mlan_private * priv, t_u8 chnl)
/* get the radar detection requirements according to chan num */
for (j = 0; j < priv->adapter->region_channel[i].num_cfp; j++) {
if (pcfp[j].channel == chnl) {
- required = pcfp[j].radar_detect;
+ required = pcfp[j].passive_scan_or_radar_detect;
break;
}
}
@@ -1146,3 +1329,50 @@ wlan_get_cfp_radar_detect(mlan_private * priv, t_u8 chnl)
LEAVE();
return required;
}
+
+/**
+ * @brief Get if scan type is passive or not on a certain channel for b/g band
+ *
+ * @param priv Private driver information structure
+ * @param chnl Channel to determine scan type
+ *
+ * @return
+ * - MTRUE if scan type is passive
+ * - MFALSE otherwise
+ */
+
+t_bool
+wlan_bg_scan_type_is_passive(mlan_private * priv, t_u8 chnl)
+{
+ int i, j;
+ t_bool passive = MFALSE;
+ chan_freq_power_t *pcfp = MNULL;
+
+ ENTER();
+
+ /* get the cfp table first */
+ for (i = 0; i < MAX_REGION_CHANNEL_NUM; i++) {
+ if (priv->adapter->region_channel[i].band & (BAND_B | BAND_G)) {
+ pcfp = priv->adapter->region_channel[i].pcfp;
+ break;
+ }
+ }
+
+ if (!pcfp) {
+ /* This means operation in BAND-B or BAND_G is not support, we can
+ just return false here */
+ goto done;
+ }
+
+ /* get the bg scan type according to chan num */
+ for (j = 0; j < priv->adapter->region_channel[i].num_cfp; j++) {
+ if (pcfp[j].channel == chnl) {
+ passive = pcfp[j].passive_scan_or_radar_detect;
+ break;
+ }
+ }
+
+ done:
+ LEAVE();
+ return passive;
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_cmdevt.c b/drivers/net/wireless/sd8797/mlan/mlan_cmdevt.c
index f3db9e662565..a3e5ef0517f0 100644
--- a/drivers/net/wireless/sd8797/mlan/mlan_cmdevt.c
+++ b/drivers/net/wireless/sd8797/mlan/mlan_cmdevt.c
@@ -344,7 +344,9 @@ wlan_dnld_cmd_to_fw(IN mlan_private * pmpriv, IN cmd_ctrl_node * pcmd_node)
mlan_ioctl_req *pioctl_buf = MNULL;
t_u16 cmd_code;
t_u16 cmd_size;
+#ifdef DEBUG_LEVEL1
t_u32 sec, usec;
+#endif
ENTER();
@@ -389,8 +391,7 @@ wlan_dnld_cmd_to_fw(IN mlan_private * pmpriv, IN cmd_ctrl_node * pcmd_node)
pcmd_node->cmdbuf->data_len = cmd_size;
- pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle, &sec,
- &usec);
+ PRINTM_GET_SYS_TIME(MCMND, &sec, &usec);
PRINTM_NETINTF(MCMND, pmpriv);
PRINTM(MCMND, "DNLD_CMD (%lu.%06lu): 0x%x, act 0x%x, len %d, seqno 0x%x\n",
sec, usec, cmd_code,
@@ -690,8 +691,9 @@ wlan_process_event(pmlan_adapter pmadapter)
pmlan_private priv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
pmlan_buffer pmbuf = pmadapter->pmlan_buffer_event;
t_u32 eventcause = pmadapter->event_cause;
- t_u32 in_ts_sec;
- t_u32 in_ts_usec;
+#ifdef DEBUG_LEVEL1
+ t_u32 in_ts_sec, in_ts_usec;
+#endif
ENTER();
/* Save the last event to debug log */
@@ -726,8 +728,7 @@ wlan_process_event(pmlan_adapter pmadapter)
if (MTRUE && (eventcause != EVENT_PS_SLEEP && eventcause != EVENT_PS_AWAKE)
) {
- pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle,
- &in_ts_sec, &in_ts_usec);
+ PRINTM_GET_SYS_TIME(MEVENT, &in_ts_sec, &in_ts_usec);
PRINTM_NETINTF(MEVENT, priv);
PRINTM(MEVENT, "%lu.%06lu : Event: 0x%x\n", in_ts_sec, in_ts_usec,
eventcause);
@@ -1109,7 +1110,10 @@ wlan_process_cmdresp(mlan_adapter * pmadapter)
t_u16 cmdresp_result;
mlan_ioctl_req *pioctl_buf = MNULL;
mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks;
- t_u32 sec, usec, i;
+#ifdef DEBUG_LEVEL1
+ t_u32 sec, usec;
+#endif
+ t_u32 i;
ENTER();
@@ -1189,8 +1193,7 @@ wlan_process_cmdresp(mlan_adapter * pmadapter)
pmadapter->dbg.last_cmd_resp_id[pmadapter->dbg.last_cmd_resp_index] =
orig_cmdresp_no;
- pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle, &sec,
- &usec);
+ PRINTM_GET_SYS_TIME(MCMND, &sec, &usec);
PRINTM_NETINTF(MCMND, pmadapter->curr_cmd->priv);
PRINTM(MCMND, "CMD_RESP (%lu.%06lu): 0x%x, result %d, len %d, seqno 0x%x\n",
sec, usec, orig_cmdresp_no, cmdresp_result, resp->size,
@@ -1301,7 +1304,9 @@ wlan_cmd_timeout_func(t_void * function_context)
mlan_adapter *pmadapter = (mlan_adapter *) function_context;
cmd_ctrl_node *pcmd_node = MNULL;
mlan_ioctl_req *pioctl_buf = MNULL;
+#ifdef DEBUG_LEVEL1
t_u32 sec, usec;
+#endif
t_u8 i;
mlan_private *pmpriv = MNULL;
@@ -1325,8 +1330,7 @@ wlan_cmd_timeout_func(t_void * function_context)
pmadapter->dbg.last_cmd_id[pmadapter->dbg.last_cmd_index];
pmadapter->dbg.timeout_cmd_act =
pmadapter->dbg.last_cmd_act[pmadapter->dbg.last_cmd_index];
- pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle, &sec,
- &usec);
+ PRINTM_GET_SYS_TIME(MERROR, &sec, &usec);
PRINTM(MERROR, "Timeout cmd id (%lu.%06lu) = 0x%x, act = 0x%x \n", sec,
usec, pmadapter->dbg.timeout_cmd_id,
pmadapter->dbg.timeout_cmd_act);
@@ -2719,6 +2723,9 @@ wlan_ret_get_hw_spec(IN pmlan_private pmpriv,
PRINTM(MWARN, "unidentified region code, use the default (0x%02x)\n",
MRVDRV_DEFAULT_REGION_CODE);
}
+ /* Synchronize CFP code with region code */
+ pmadapter->cfp_code_bg = pmadapter->region_code;
+ pmadapter->cfp_code_a = pmadapter->region_code;
if (wlan_set_regiontable(pmpriv, (t_u8) pmadapter->region_code,
pmadapter->fw_bands)) {
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_decl.h b/drivers/net/wireless/sd8797/mlan/mlan_decl.h
index d0ca7acae937..41cf2bf5f2f1 100644
--- a/drivers/net/wireless/sd8797/mlan/mlan_decl.h
+++ b/drivers/net/wireless/sd8797/mlan/mlan_decl.h
@@ -27,7 +27,7 @@ Change log:
#define _MLAN_DECL_H_
/** MLAN release version */
-#define MLAN_RELEASE_VERSION "303"
+#define MLAN_RELEASE_VERSION "311"
/** Re-define generic data types for MLAN/MOAL */
/** Signed char (1-byte) */
@@ -136,10 +136,18 @@ typedef t_s32 t_sval;
/** This is current limit on Maximum Rx AMPDU allowed */
#define MLAN_MAX_RX_BASTREAM_SUPPORTED 16
+#ifdef STA_SUPPORT
/** Default Win size attached during ADDBA request */
-#define MLAN_AMPDU_DEF_TXWINSIZE 32
+#define MLAN_STA_AMPDU_DEF_TXWINSIZE 16
/** Default Win size attached during ADDBA response */
-#define MLAN_AMPDU_DEF_RXWINSIZE 16
+#define MLAN_STA_AMPDU_DEF_RXWINSIZE 32
+#endif /* STA_SUPPORT */
+#ifdef UAP_SUPPORT
+/** Default Win size attached during ADDBA request */
+#define MLAN_UAP_AMPDU_DEF_TXWINSIZE 32
+/** Default Win size attached during ADDBA response */
+#define MLAN_UAP_AMPDU_DEF_RXWINSIZE 16
+#endif /* UAP_SUPPORT */
/** Block ack timeout value */
#define MLAN_DEFAULT_BLOCK_ACK_TIMEOUT 0xffff
/** Maximum Tx Win size configured for ADDBA request [10 bits] */
@@ -626,6 +634,8 @@ typedef MLAN_PACK_START struct _custom_ie
t_u8 ie_buffer[MAX_IE_SIZE];
} MLAN_PACK_END custom_ie;
+/** Max IE index to FW */
+#define MAX_MGMT_IE_INDEX_TO_FW 4
/** Max IE index per BSS */
#define MAX_MGMT_IE_INDEX 16
@@ -659,7 +669,7 @@ typedef MLAN_PACK_START struct _tlvbuf_custom_ie
/** Length */
t_u16 len;
/** IE data */
- custom_ie ie_data_list[MAX_MGMT_IE_INDEX];
+ custom_ie ie_data_list[MAX_MGMT_IE_INDEX_TO_FW];
/** Max mgmt IE TLV */
tlvbuf_max_mgmt_ie max_mgmt_ie;
} MLAN_PACK_END mlan_ds_misc_custom_ie;
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_fw.h b/drivers/net/wireless/sd8797/mlan/mlan_fw.h
index 1b0af8d8c0ea..fda2e7285dfd 100644
--- a/drivers/net/wireless/sd8797/mlan/mlan_fw.h
+++ b/drivers/net/wireless/sd8797/mlan/mlan_fw.h
@@ -148,6 +148,11 @@ typedef enum _KEY_TYPE_ID
KEY_TYPE_ID_WAPI,
} KEY_TYPE_ID;
+/** Key Info flag for multicast key */
+#define KEY_INFO_MCAST_KEY 0x01
+/** Key Info flag for unicast key */
+#define KEY_INFO_UCAST_KEY 0x02
+
/** KEY_INFO_WEP*/
typedef enum _KEY_INFO_WEP
{
@@ -311,9 +316,10 @@ typedef enum _WLAN_802_11_WEP_STATUS
#define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 0x16) // 0x0116
/** TLV type : Beacon SNR high */
#define TLV_TYPE_SNR_HIGH (PROPRIETARY_TLV_BASE_ID + 0x17) // 0x0117
-
/** TLV type : Start BG scan later */
#define TLV_TYPE_STARTBGSCANLATER (PROPRIETARY_TLV_BASE_ID + 0x1e) // 0x011e
+/** TLV type: BG scan repeat count */
+#define TLV_TYPE_REPEAT_COUNT (PROPRIETARY_TLV_BASE_ID + 0xb0) // 0x01b0
/** TLV type : Authentication type */
#define TLV_TYPE_AUTH_TYPE (PROPRIETARY_TLV_BASE_ID + 0x1f) // 0x011f
/** TLV type : BSSID */
@@ -397,7 +403,7 @@ typedef enum _WLAN_802_11_WEP_STATUS
#define BA_STREAM_NOT_ALLOWED 0xff
/** Test if 11n is enabled by checking the HTCap IE */
-#define IS_11N_ENABLED(priv) ((priv->adapter->config_bands & BAND_GN ||priv->adapter->config_bands & BAND_AN) \
+#define IS_11N_ENABLED(priv) ((priv->config_bands & BAND_GN ||priv->config_bands & BAND_AN) \
&& priv->curr_bss_params.bss_descriptor.pht_cap)
/** Find out if we are the initiator or not */
#define INITIATOR_BIT(DelBAParamSet) (((DelBAParamSet) & \
@@ -848,6 +854,9 @@ typedef enum _WLAN_802_11_WEP_STATUS
#define HostCmd_CMD_802_11_REMAIN_ON_CHANNEL 0x010d
#endif
+/** Host Command ID : OTP user data */
+#define HostCmd_CMD_OTP_READ_USER_DATA 0x0114
+
/** Enhanced PS modes */
typedef enum _ENH_PS_MODES
{
@@ -2806,6 +2815,25 @@ typedef MLAN_PACK_START struct _HostCmd_DS_802_11_BG_SCAN_QUERY_RSP
HostCmd_DS_802_11_SCAN_RSP scan_resp;
} MLAN_PACK_END HostCmd_DS_802_11_BG_SCAN_QUERY_RSP;
+/** MrvlIEtypes_StartLater_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_StartLater_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /* 0 - BGScan start immediately, 1 - BGScan will start later after "Scan
+ Interval" */
+ t_u16 value;
+} MLAN_PACK_END MrvlIEtypes_StartLater_t;
+
+/** MrvlIEtypes_RepeatCount_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_RepeatCount_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /* Repeat count */
+ t_u16 repeat_count;
+} MLAN_PACK_END MrvlIEtypes_RepeatCount_t;
+
/** MrvlIEtypes_DomainParamSet_t */
typedef MLAN_PACK_START struct _MrvlIEtypes_DomainParamSet
{
@@ -3540,6 +3568,19 @@ typedef MLAN_PACK_START struct _HostCmd_DS_SUBSCRIBE_EVENT
t_u16 event_bitmap;
} MLAN_PACK_END HostCmd_DS_SUBSCRIBE_EVENT;
+/** HostCmd_DS_OTP_USER_DATA */
+typedef MLAN_PACK_START struct _HostCmd_DS_OTP_USER_DATA
+{
+ /** Action */
+ t_u16 action;
+ /** Reserved field */
+ t_u16 reserved;
+ /** User data length */
+ t_u16 user_data_length;
+ /** User data */
+ t_u8 user_data[1];
+} MLAN_PACK_END HostCmd_DS_OTP_USER_DATA;
+
/** HostCmd_DS_INACTIVITY_TIMEOUT_EXT */
typedef MLAN_PACK_START struct _HostCmd_DS_INACTIVITY_TIMEOUT_EXT
{
@@ -4495,6 +4536,7 @@ typedef struct MLAN_PACK_START _HostCmd_DS_COMMAND
HostCmd_DS_802_11_BG_SCAN_QUERY bg_scan_query;
HostCmd_DS_802_11_BG_SCAN_QUERY_RSP bg_scan_query_resp;
HostCmd_DS_SUBSCRIBE_EVENT subscribe_event;
+ HostCmd_DS_OTP_USER_DATA otp_user_data;
/** Associate */
HostCmd_DS_802_11_ASSOCIATE associate;
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_ieee.h b/drivers/net/wireless/sd8797/mlan/mlan_ieee.h
index 9473c498b973..2431e06f48fa 100644
--- a/drivers/net/wireless/sd8797/mlan/mlan_ieee.h
+++ b/drivers/net/wireless/sd8797/mlan/mlan_ieee.h
@@ -27,6 +27,8 @@ Change log:
#ifndef _MLAN_IEEE_H_
#define _MLAN_IEEE_H_
+/** FIX IES size in beacon buffer */
+#define WLAN_802_11_FIXED_IE_SIZE 12
/** WLAN supported rates */
#define WLAN_SUPPORTED_RATES 14
@@ -1179,6 +1181,8 @@ typedef MLAN_PACK_START struct
t_u8 rssi_threshold;
/** SNR threshold */
t_u8 snr_threshold;
+ /** repeat count */
+ t_u16 repeat_count;
/** SSID filter list used in the to limit the scan results */
wlan_user_scan_ssid ssid_list[MRVDRV_MAX_SSID_LIST_LENGTH];
/** Variable number (fixed maximum) of channels to scan up */
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_init.c b/drivers/net/wireless/sd8797/mlan/mlan_init.c
index 563f74cd3980..48681b3e3ed9 100644
--- a/drivers/net/wireless/sd8797/mlan/mlan_init.c
+++ b/drivers/net/wireless/sd8797/mlan/mlan_init.c
@@ -312,10 +312,17 @@ wlan_init_priv(pmlan_private priv)
priv->bcn_rssi_avg = 0;
priv->bcn_nf_avg = 0;
priv->bcn_nf_last = 0;
+
+ priv->sec_info.ewpa_enabled = MFALSE;
+ priv->sec_info.wpa_enabled = MFALSE;
+ priv->sec_info.wpa2_enabled = MFALSE;
memset(pmadapter, &priv->wpa_ie, 0, sizeof(priv->wpa_ie));
memset(pmadapter, &priv->aes_key, 0, sizeof(priv->aes_key));
priv->wpa_ie_len = 0;
priv->wpa_is_gtk_set = MFALSE;
+ priv->sec_info.wapi_enabled = MFALSE;
+ priv->wapi_ie_len = 0;
+ priv->sec_info.wapi_key_on = MFALSE;
memset(pmadapter, &priv->wps, 0, sizeof(priv->wps));
memset(pmadapter, &priv->gen_ie_buf, 0, sizeof(priv->gen_ie_buf));
@@ -362,7 +369,6 @@ wlan_init_priv(pmlan_private priv)
t_void
wlan_init_adapter(pmlan_adapter pmadapter)
{
- int i;
opt_sleep_confirm_buffer *sleep_cfm_buf = MNULL;
ENTER();
@@ -391,9 +397,6 @@ wlan_init_adapter(pmlan_adapter pmadapter)
pmadapter->mp_wr_bitmap = 0;
pmadapter->curr_rd_port = 1;
pmadapter->curr_wr_port = 1;
- for (i = 0; i < MAX_NUM_TID; i++) {
- pmadapter->tx_eligibility[i] = 1;
- }
pmadapter->mp_data_port_mask = DATA_PORT_MASK;
#ifdef SDIO_MULTI_PORT_TX_AGGR
@@ -559,6 +562,8 @@ wlan_init_adapter(pmlan_adapter pmadapter)
memset(pmadapter, &pmadapter->region_channel, 0,
sizeof(pmadapter->region_channel));
pmadapter->region_code = 0;
+ memcpy(pmadapter, pmadapter->country_code, MRVDRV_DEFAULT_COUNTRY_CODE,
+ COUNTRY_CODE_LEN);
pmadapter->bcn_miss_time_out = DEFAULT_BCN_MISS_TIMEOUT;
pmadapter->adhoc_awake_period = 0;
#ifdef STA_SUPPORT
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_ioctl.h b/drivers/net/wireless/sd8797/mlan/mlan_ioctl.h
index 15e88e631067..964de9197ffe 100644
--- a/drivers/net/wireless/sd8797/mlan/mlan_ioctl.h
+++ b/drivers/net/wireless/sd8797/mlan/mlan_ioctl.h
@@ -82,6 +82,7 @@ enum _mlan_ioctl_req_id
MLAN_OID_SNMP_MIB_DOT11D,
MLAN_OID_SNMP_MIB_DOT11H,
#endif
+ MLAN_OID_SNMP_MIB_DTIM_PERIOD,
/* Status Information Group */
MLAN_IOCTL_GET_INFO = 0x00050000,
@@ -204,12 +205,15 @@ enum _mlan_ioctl_req_id
MLAN_OID_MISC_IP_ADDR,
MLAN_OID_MISC_MAC_CONTROL,
MLAN_OID_MISC_MEF_CFG,
+ MLAN_OID_MISC_CFP_CODE,
+ MLAN_OID_MISC_COUNTRY_CODE,
MLAN_OID_MISC_THERMAL,
MLAN_OID_MISC_RX_MGMT_IND,
MLAN_OID_MISC_SUBSCRIBE_EVENT,
#ifdef DEBUG_LEVEL1
MLAN_OID_MISC_DRVDBG,
#endif
+ MLAN_OID_MISC_OTP_USER_DATA,
};
/** Sub command size */
@@ -1041,6 +1045,8 @@ typedef struct _mlan_ds_snmp_mib
/** OID value for MLAN_OID_SNMP_MIB_DOT11D/H */
t_u32 oid_value;
#endif
+ /** DTIM period for MLAN_OID_SNMP_MIB_DTIM_PERIOD */
+ t_u32 dtim_period;
} param;
} mlan_ds_snmp_mib, *pmlan_ds_snmp_mib;
@@ -1266,6 +1272,8 @@ typedef struct _mlan_bss_info
#ifdef STA_SUPPORT
/** Capability Info */
t_u16 capability_info;
+ /** Beacon Interval */
+ t_u16 beacon_interval;
/** Listen Interval */
t_u16 listen_interval;
/** Association Id */
@@ -1442,7 +1450,7 @@ typedef struct _mlan_debug_info
#ifdef UAP_SUPPORT
/** Maximum number of clients supported by AP */
-#define MAX_NUM_CLIENTS 16
+#define MAX_NUM_CLIENTS MAX_STA_COUNT
/** station info */
typedef struct _sta_info
@@ -1553,7 +1561,7 @@ enum _mlan_psk_type
/** key flag for rx_seq */
#define KEY_FLAG_RX_SEQ_VALID 0x00000002
/** key flag for group key */
-#define KEY_FLAG_GROUP_KEY 0x00000004
+#define KEY_FLAG_GROUP_KEY 0x00000004
/** key flag for tx and rx */
#define KEY_FLAG_SET_TX_KEY 0x00000008
/** key flag for remove key */
@@ -1600,6 +1608,24 @@ typedef struct _mlan_pmk_t
t_u8 pmk[MLAN_MAX_KEY_LENGTH];
} mlan_pmk_t;
+/** Embedded supplicant RSN type: No RSN */
+#define RSN_TYPE_NO_RSN MBIT(0)
+/** Embedded supplicant RSN type: WPA */
+#define RSN_TYPE_WPA MBIT(3)
+/** Embedded supplicant RSN type: WPA-NONE */
+#define RSN_TYPE_WPANONE MBIT(4)
+/** Embedded supplicant RSN type: WPA2 */
+#define RSN_TYPE_WPA2 MBIT(5)
+/** Embedded supplicant RSN type: RFU */
+#define RSN_TYPE_VALID_BITS (RSN_TYPE_NO_RSN | RSN_TYPE_WPA | RSN_TYPE_WPANONE | RSN_TYPE_WPA2)
+
+/** Embedded supplicant cipher type: TKIP */
+#define EMBED_CIPHER_TKIP MBIT(2)
+/** Embedded supplicant cipher type: AES */
+#define EMBED_CIPHER_AES MBIT(3)
+/** Embedded supplicant cipher type: RFU */
+#define EMBED_CIPHER_VALID_BITS (EMBED_CIPHER_TKIP | EMBED_CIPHER_AES)
+
/** Type definition of mlan_ds_passphrase for MLAN_OID_SEC_CFG_PASSPHRASE */
typedef struct _mlan_ds_passphrase
{
@@ -2545,7 +2571,7 @@ enum _mlan_reg_type
MLAN_REG_MAC = 1,
MLAN_REG_BBP,
MLAN_REG_RF,
- MLAN_REG_CAU,
+ MLAN_REG_CAU = 5,
};
/** Type definition of mlan_ds_reg_rw for MLAN_OID_REG_RW */
@@ -2782,6 +2808,22 @@ typedef struct _mlan_ds_misc_mef_cfg
} param;
} mlan_ds_misc_mef_cfg;
+/** Type definition of mlan_ds_misc_cfp_code for MLAN_OID_MISC_CFP_CODE */
+typedef struct _mlan_ds_misc_cfp_code
+{
+ /** CFP table code for 2.4GHz */
+ t_u32 cfp_code_bg;
+ /** CFP table code for 5GHz */
+ t_u32 cfp_code_a;
+} mlan_ds_misc_cfp_code;
+
+/** Type definition of mlan_ds_misc_country_code for MLAN_OID_MISC_COUNTRY_CODE */
+typedef struct _mlan_ds_misc_country_code
+{
+ /** Country Code */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+} mlan_ds_misc_country_code;
+
/** BITMAP for subscribe event rssi low */
#define SUBSCRIBE_EVT_RSSI_LOW MBIT(0)
/** BITMAP for subscribe event snr low */
@@ -2806,6 +2848,8 @@ typedef struct _mlan_ds_misc_mef_cfg
#define SUBSCRIBE_EVT_LINK_QUALITY MBIT(10)
/** BITMAP for subscribe event pre_beacon_lost */
#define SUBSCRIBE_EVT_PRE_BEACON_LOST MBIT(11)
+/** default PRE_BEACON_MISS_COUNT */
+#define DEFAULT_PRE_BEACON_MISS 30
/** Type definition of mlan_ds_subscribe_evt for MLAN_OID_MISC_CFP_CODE */
typedef struct _mlan_ds_subscribe_evt
@@ -2868,6 +2912,20 @@ typedef struct _mlan_ds_subscribe_evt
t_u8 pre_beacon_miss;
} mlan_ds_subscribe_evt;
+/** Max OTP user data length */
+#define MAX_OTP_USER_DATA_LEN 252
+
+/** Type definition of mlan_ds_misc_otp_user_data for MLAN_OID_MISC_OTP_USER_DATA */
+typedef struct _mlan_ds_misc_otp_user_data
+{
+ /** Reserved */
+ t_u16 reserved;
+ /** OTP user data length */
+ t_u16 user_data_length;
+ /** User data buffer */
+ t_u8 user_data[MAX_OTP_USER_DATA_LEN];
+} mlan_ds_misc_otp_user_data;
+
/** Type definition of mlan_ds_misc_cfg for MLAN_IOCTL_MISC_CFG */
typedef struct _mlan_ds_misc_cfg
{
@@ -2902,6 +2960,10 @@ typedef struct _mlan_ds_misc_cfg
t_u32 mac_ctrl;
/** MEF configuration for MLAN_OID_MISC_MEF_CFG */
mlan_ds_misc_mef_cfg mef_cfg;
+ /** CFP code for MLAN_OID_MISC_CFP_CODE */
+ mlan_ds_misc_cfp_code cfp_code;
+ /** Country code for MLAN_OID_MISC_COUNTRY_CODE */
+ mlan_ds_misc_country_code country_code;
/** Thermal reading for MLAN_OID_MISC_THERMAL */
t_u32 thermal;
/** Mgmt subtype mask for MLAN_OID_MISC_RX_MGMT_IND */
@@ -2912,6 +2974,7 @@ typedef struct _mlan_ds_misc_cfg
/** Driver debug bit masks */
t_u32 drvdbg;
#endif
+ mlan_ds_misc_otp_user_data otp_user_data;
} param;
} mlan_ds_misc_cfg, *pmlan_ds_misc_cfg;
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_main.h b/drivers/net/wireless/sd8797/mlan/mlan_main.h
index fb15c7226c38..44e4f8001201 100644
--- a/drivers/net/wireless/sd8797/mlan/mlan_main.h
+++ b/drivers/net/wireless/sd8797/mlan/mlan_main.h
@@ -4,7 +4,7 @@
* structures and declares global function prototypes used
* in MLAN module.
*
- * Copyright (C) 2008-2011, Marvell International Ltd.
+ * Copyright (C) 2008-2012, Marvell International Ltd.
*
* This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
@@ -31,6 +31,11 @@ Change log:
#ifdef DEBUG_LEVEL1
extern t_void(*print_callback) (IN t_void * pmoal_handle,
IN t_u32 level, IN t_s8 * pformat, IN ...);
+
+extern mlan_status(*get_sys_time_callback) (IN t_void * pmoal_handle,
+ OUT t_u32 * psec,
+ OUT t_u32 * pusec);
+
extern t_u32 drvdbg;
#ifdef DEBUG_LEVEL2
@@ -40,10 +45,35 @@ extern t_u32 drvdbg;
print_callback(MNULL, MWARN, msg);} while(0)
#define PRINTM_MENTRY(msg...) do {if ((drvdbg & MENTRY) && (print_callback)) \
print_callback(MNULL, MENTRY, msg);} while(0)
+#define PRINTM_GET_SYS_TIME(level, psec, pusec) \
+do { \
+ if ((level & drvdbg) && (get_sys_time_callback)) \
+ get_sys_time_callback(MNULL, psec, pusec); \
+} while (0)
+
+/** Hexdump for level-2 debugging */
+#define HEXDUMP(x,y,z) \
+do { \
+ if ((drvdbg & (MHEX_DUMP | MINFO)) && (print_callback)) \
+ print_callback(MNULL, MHEX_DUMP | MINFO, x, y, z); \
+} while (0)
+
#else
+
#define PRINTM_MINFO(msg...) do {} while (0)
#define PRINTM_MWARN(msg...) do {} while (0)
#define PRINTM_MENTRY(msg...) do {} while (0)
+
+#define PRINTM_GET_SYS_TIME(level, psec, pusec) \
+do { \
+ if ((level & drvdbg) && (get_sys_time_callback) \
+ && (level != MINFO) && (level != MWARN)) \
+ get_sys_time_callback(MNULL, psec, pusec); \
+} while (0)
+
+/** Hexdump for debugging */
+#define HEXDUMP(x,y,z) do {} while (0)
+
#endif /* DEBUG_LEVEL2 */
#define PRINTM_MFW_D(msg...) do {if ((drvdbg & MFW_D) && (print_callback)) \
@@ -74,20 +104,6 @@ extern t_u32 drvdbg;
#define PRINTM(level,msg...) PRINTM_##level(msg)
-#ifdef DEBUG_LEVEL2
-
-/** Hexdump for level-2 debugging */
-#define HEXDUMP(x,y,z) \
-do { \
- if ((drvdbg & (MHEX_DUMP | MINFO)) && (print_callback)) \
- print_callback(MNULL, MHEX_DUMP | MINFO, x, y, z); \
-} while (0)
-#else
-
-/** Hexdump for debugging */
-#define HEXDUMP(x,y,z) do {} while (0)
-#endif /* DEBUG_LEVEL2 */
-
/** Log debug message */
#ifdef __GNUC__
#define PRINTM_NETINTF(level, pmpriv) \
@@ -122,6 +138,8 @@ do { \
/** Hexdump for debugging */
#define HEXDUMP(x,y,z) do {} while (0)
+#define PRINTM_GET_SYS_TIME(level, psec, pusec) do { } while(0)
+
#endif /* DEBUG_LEVEL1 */
/** Log entry point for debugging */
@@ -330,11 +348,19 @@ do { \
#define MLAN_DEFAULT_LISTEN_INTERVAL 10
/** Maximum number of region codes */
-#define MRVDRV_MAX_REGION_CODE 8
+#define MRVDRV_MAX_REGION_CODE 9
+
+/** Maximum number of CFP codes for BG */
+#define MRVDRV_MAX_CFP_CODE_BG 0
+/** Maximum number of CFP codes for A */
+#define MRVDRV_MAX_CFP_CODE_A 5
/** Default region code */
#define MRVDRV_DEFAULT_REGION_CODE 0x10
+/** Default country code */
+#define MRVDRV_DEFAULT_COUNTRY_CODE "US"
+
/** Default factor for calculating beacon average */
#define DEFAULT_BCN_AVG_FACTOR 8
/** Default factor for calculating data average */
@@ -722,8 +748,9 @@ typedef struct _chan_freq_power_t
t_u32 freq;
/** Max allowed Tx power level */
t_u16 max_tx_power;
- /** TRUE:radar detect required; FALSE:radar detect not required*/
- t_bool radar_detect;
+ /** TRUE:radar detect required for BAND A or passive scan for BAND B/G;
+ * FALSE:radar detect not required for BAND A or active scan for BAND B/G*/
+ t_bool passive_scan_or_radar_detect;
/** TRUE:channel unsupported; FALSE:supported */
t_u8 unsupported;
} chan_freq_power_t;
@@ -1368,7 +1395,7 @@ typedef struct _sdio_mpa_tx
/** multiport tx aggregation packet count */
t_u32 pkt_cnt;
/** multiport tx aggregation ports */
- t_u16 ports;
+ t_u32 ports;
/** multiport tx aggregation starting port */
t_u16 start_port;
/** multiport tx aggregation enable/disable flag */
@@ -1393,7 +1420,7 @@ typedef struct _sdio_mpa_rx
/** multiport rx aggregation packet count */
t_u32 pkt_cnt;
/** multiport rx aggregation ports */
- t_u16 ports;
+ t_u32 ports;
/** multiport rx aggregation starting port */
t_u16 start_port;
@@ -1511,8 +1538,6 @@ typedef struct _mlan_adapter
t_u8 *mp_regs;
/** allocated buf to read SDIO multiple port group registers */
t_u8 *mp_regs_buf;
- /** Array to store data transfer eligibility based on tid (QoS-over-SDIO) */
- t_u8 tx_eligibility[MAX_NUM_TID];
#ifdef SDIO_MULTI_PORT_TX_AGGR
/** data structure for SDIO MPA TX */
@@ -1596,6 +1621,10 @@ typedef struct _mlan_adapter
t_u16 region_code;
/** Region Channel data */
region_chan_t region_channel[MAX_REGION_CHANNEL_NUM];
+ /** CFP table code for 2.4GHz */
+ t_u8 cfp_code_bg;
+ /** CFP table code for 5GHz */
+ t_u8 cfp_code_a;
#ifdef STA_SUPPORT
/** Universal Channel data */
region_chan_t universal_channel[MAX_REGION_CHANNEL_NUM];
@@ -1604,6 +1633,8 @@ typedef struct _mlan_adapter
#endif /* STA_SUPPORT */
/** 11D and Domain Regulatory Data */
wlan_802_11d_domain_reg_t domain_reg;
+ /** Country Code */
+ t_u8 country_code[COUNTRY_CODE_LEN];
/** FSM variable for 11h support */
wlan_11h_device_state_t state_11h;
/** FSM variable for DFS support */
@@ -1620,6 +1651,7 @@ typedef struct _mlan_adapter
BSSDescriptor_t *pscan_table;
/** scan age in secs */
t_u32 age_in_secs;
+ t_u8 bgscan_reported;
/** Number of records in the scan table */
t_u32 num_in_scan_table;
@@ -2177,6 +2209,9 @@ mlan_status wlan_cmd_bgscan_config(IN mlan_private * pmpriv,
mlan_status wlan_ret_bgscan_config(IN mlan_private * pmpriv,
IN HostCmd_DS_COMMAND * resp,
IN mlan_ioctl_req * pioctl_buf);
+mlan_status wlan_ret_802_11_bgscan_query(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf);
/** Get Channel-Frequency-Power by band and channel */
chan_freq_power_t *wlan_get_cfp_by_band_and_channel(pmlan_adapter pmadapter,
@@ -2221,10 +2256,16 @@ int wlan_get_rate_index(pmlan_adapter pmadapter, t_u16 * rateBitmap, int size);
/* CFP related functions */
/** Region code index table */
extern t_u16 region_code_index[MRVDRV_MAX_REGION_CODE];
+/** The table to keep CFP code for BG */
+extern t_u16 cfp_code_index_bg[MRVDRV_MAX_CFP_CODE_BG];
+/** The table to keep CFP code for A */
+extern t_u16 cfp_code_index_a[MRVDRV_MAX_CFP_CODE_A];
/** Set region table */
mlan_status wlan_set_regiontable(mlan_private * pmpriv, t_u8 region, t_u8 band);
/** Get radar detection requirements*/
t_bool wlan_get_cfp_radar_detect(mlan_private * priv, t_u8 chnl);
+/** check if scan type is passive for b/g band*/
+t_bool wlan_bg_scan_type_is_passive(mlan_private * priv, t_u8 chnl);
/* 802.11D related functions */
/** Initialize 11D */
@@ -2280,6 +2321,12 @@ mlan_status wlan_11d_handle_uap_domain_info(mlan_private * pmpriv,
t_void * pioctl_buf);
#endif
+/** This function converts region string to CFP table code */
+mlan_status wlan_misc_country_2_cfp_table_code(IN pmlan_adapter pmadapter,
+ IN t_u8 * country_code,
+ OUT t_u8 * cfp_bg,
+ OUT t_u8 * cfp_a);
+
/** check if station list is empty */
t_u8 wlan_is_station_list_empty(mlan_private * priv);
/** get station node */
@@ -2316,7 +2363,6 @@ wlan_is_tx_pause(mlan_private * priv, t_u8 * ra)
t_void wlan_updata_ralist_tx_pause(pmlan_private priv, t_u8 * mac,
t_u8 tx_pause);
-sta_node *wlan_get_tx_pause_station_entry(mlan_private * priv);
#ifdef UAP_SUPPORT
mlan_status wlan_process_uap_rx_packet(IN mlan_private * priv,
@@ -2366,6 +2412,9 @@ mlan_status wlan_set_drvdbg(IN pmlan_adapter pmadapter,
IN pmlan_ioctl_req pioctl_req);
#endif
+mlan_status wlan_misc_otp_user_data(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req);
+
/**
* @brief RA based queueing
*
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_misc.c b/drivers/net/wireless/sd8797/mlan/mlan_misc.c
index 929a38ab33f6..f41dcea3d206 100644
--- a/drivers/net/wireless/sd8797/mlan/mlan_misc.c
+++ b/drivers/net/wireless/sd8797/mlan/mlan_misc.c
@@ -970,7 +970,7 @@ wlan_misc_ioctl_custom_ie_list(IN pmlan_adapter pmadapter,
goto done;
}
memset(pmadapter, ie_data, 0,
- sizeof(custom_ie) * MAX_MGMT_IE_INDEX);
+ sizeof(custom_ie) * MAX_MGMT_IE_INDEX_TO_FW);
len = 0;
for (i = 0; i < pmadapter->max_mgmt_ie_index; i++) {
memcpy(pmadapter, (t_u8 *) ie_data + len, &i,
@@ -1042,7 +1042,7 @@ wlan_misc_ioctl_custom_ie_list(IN pmlan_adapter pmadapter,
goto done;
}
memset(pmadapter, ie_data, 0,
- sizeof(custom_ie) * MAX_MGMT_IE_INDEX);
+ sizeof(custom_ie) * MAX_MGMT_IE_INDEX_TO_FW);
memcpy(pmadapter, (t_u8 *) ie_data, &pmpriv->mgmt_ie[index],
pmpriv->mgmt_ie[index].ie_length +
MLAN_CUSTOM_IE_HDR_SIZE);
@@ -1281,41 +1281,6 @@ wlan_delete_station_list(pmlan_private priv)
}
/**
- * @brief This function will return the pointer to station entry in station list
- * table which in tx_pause state
- *
- * @param priv A pointer to mlan_private
- *
- * @return A pointer to structure sta_node
- */
-sta_node *
-wlan_get_tx_pause_station_entry(mlan_private * priv)
-{
- sta_node *sta_ptr;
-
- ENTER();
-
- if (!(sta_ptr = (sta_node *) util_peek_list(priv->adapter->pmoal_handle,
- &priv->sta_list,
- priv->adapter->callbacks.
- moal_spin_lock,
- priv->adapter->callbacks.
- moal_spin_unlock))) {
- LEAVE();
- return MNULL;
- }
- while (sta_ptr != (sta_node *) & priv->sta_list) {
- if (sta_ptr->tx_pause) {
- LEAVE();
- return sta_ptr;
- }
- sta_ptr = sta_ptr->pnext;
- }
- LEAVE();
- return MNULL;
-}
-
-/**
* @brief Get extended version information
*
* @param pmadapter A pointer to mlan_adapter structure
@@ -1496,6 +1461,44 @@ wlan_process_802dot11_mgmt_pkt(IN mlan_private * priv,
}
/**
+ * @brief Get OTP user data
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status
+wlan_misc_otp_user_data(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ mlan_status ret = MLAN_STATUS_FAILURE;
+
+ ENTER();
+
+ if (misc->param.otp_user_data.user_data_length > MAX_OTP_USER_DATA_LEN) {
+ PRINTM(MERROR, "Invalid OTP user data length\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return ret;
+ }
+
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_OTP_READ_USER_DATA,
+ HostCmd_ACT_GEN_GET,
+ 0,
+ (t_void *) pioctl_req, &misc->param.otp_user_data);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
* @brief This function will search for the specific ie
*
*
@@ -1718,26 +1721,26 @@ wlan_rate_ioctl_get_rate_value(IN pmlan_adapter pmadapter,
/* If not connected, set rate to the lowest in each band */
if (pmpriv->media_connected != MTRUE) {
- if (pmadapter->config_bands & (BAND_B | BAND_G)) {
+ if (pmpriv->config_bands & (BAND_B | BAND_G)) {
/* Return the lowest supported rate for BG band */
rate->param.rate_cfg.rate = SupportedRates_BG[0] & 0x7f;
- } else if (pmadapter->config_bands & (BAND_A | BAND_B)) {
+ } else if (pmpriv->config_bands & (BAND_A | BAND_B)) {
/* Return the lowest supported rate for A band */
rate->param.rate_cfg.rate = SupportedRates_BG[0] & 0x7f;
- } else if (pmadapter->config_bands & BAND_A) {
+ } else if (pmpriv->config_bands & BAND_A) {
/* Return the lowest supported rate for A band */
rate->param.rate_cfg.rate = SupportedRates_A[0] & 0x7f;
- } else if (pmadapter->config_bands & BAND_G) {
+ } else if (pmpriv->config_bands & BAND_G) {
/* Return the lowest supported rate for G band */
rate->param.rate_cfg.rate = SupportedRates_G[0] & 0x7f;
- } else if (pmadapter->config_bands & BAND_B) {
+ } else if (pmpriv->config_bands & BAND_B) {
/* Return the lowest supported rate for B band */
rate->param.rate_cfg.rate = SupportedRates_B[0] & 0x7f;
- } else if (pmadapter->config_bands & BAND_GN) {
+ } else if (pmpriv->config_bands & BAND_GN) {
/* Return the lowest supported rate for N band */
rate->param.rate_cfg.rate = SupportedRates_N[0] & 0x7f;
} else {
- PRINTM(MMSG, "Invalid Band 0x%x\n", pmadapter->config_bands);
+ PRINTM(MMSG, "Invalid Band 0x%x\n", pmpriv->config_bands);
}
} else {
@@ -1793,7 +1796,7 @@ wlan_rate_ioctl_set_rate_value(IN pmlan_adapter pmadapter,
memset(pmadapter, rates, 0, sizeof(rates));
wlan_get_active_data_rates(pmpriv, pmpriv->bss_mode,
(pmpriv->bss_mode == MLAN_BSS_MODE_INFRA) ?
- pmadapter->config_bands : pmadapter->
+ pmpriv->config_bands : pmadapter->
adhoc_start_band, rates);
rate = rates;
for (i = 0; (rate[i] && i < WLAN_SUPPORTED_RATES); i++) {
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_scan.c b/drivers/net/wireless/sd8797/mlan/mlan_scan.c
index 2c4eadf04a2e..895fb38a5786 100644
--- a/drivers/net/wireless/sd8797/mlan/mlan_scan.c
+++ b/drivers/net/wireless/sd8797/mlan/mlan_scan.c
@@ -5,7 +5,7 @@
* IOCTL handlers as well as command preparation and response routines
* for sending scan commands to the firmware.
*
- * Copyright (C) 2008-2011, Marvell International Ltd.
+ * Copyright (C) 2008-2012, Marvell International Ltd.
*
* This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
@@ -378,6 +378,9 @@ wlan_scan_create_channel_list(IN mlan_private * pmpriv,
break;
case BAND_B:
case BAND_G:
+ if (wlan_bg_scan_type_is_passive(pmpriv, (t_u8) cfp->channel)) {
+ scan_type = MLAN_SCAN_TYPE_PASSIVE;
+ }
default:
pscan_chan_list[chan_idx].radio_type =
HostCmd_SCAN_RADIO_TYPE_BG;
@@ -825,7 +828,7 @@ wlan_scan_setup_scan_config(IN mlan_private * pmpriv,
rates_size = wlan_get_supported_rates(pmpriv, pmpriv->bss_mode,
(pmpriv->bss_mode ==
- MLAN_BSS_MODE_INFRA) ? pmadapter->
+ MLAN_BSS_MODE_INFRA) ? pmpriv->
config_bands : pmadapter->
adhoc_start_band, rates);
@@ -838,13 +841,12 @@ wlan_scan_setup_scan_config(IN mlan_private * pmpriv,
PRINTM(MINFO, "SCAN_CMD: Rates size = %d\n", rates_size);
if (ISSUPP_11NENABLED(pmpriv->adapter->fw_cap_info)
- && (pmpriv->adapter->config_bands & BAND_GN
- || pmpriv->adapter->config_bands & BAND_AN)) {
+ && (pmpriv->config_bands & BAND_GN || pmpriv->config_bands & BAND_AN)) {
pht_cap = (MrvlIETypes_HTCap_t *) ptlv_pos;
memset(pmadapter, pht_cap, 0, sizeof(MrvlIETypes_HTCap_t));
pht_cap->header.type = wlan_cpu_to_le16(HT_CAPABILITY);
pht_cap->header.len = sizeof(HTCap_t);
- wlan_fill_ht_cap_tlv(pmpriv, pht_cap, pmpriv->adapter->config_bands);
+ wlan_fill_ht_cap_tlv(pmpriv, pht_cap, pmpriv->config_bands);
HEXDUMP("SCAN: HT_CAPABILITIES IE", (t_u8 *) pht_cap,
sizeof(MrvlIETypes_HTCap_t));
ptlv_pos += sizeof(MrvlIETypes_HTCap_t);
@@ -898,6 +900,11 @@ wlan_scan_setup_scan_config(IN mlan_private * pmpriv,
scan_type = MLAN_SCAN_TYPE_PASSIVE;
}
}
+ if (radio_type == HostCmd_SCAN_RADIO_TYPE_BG) {
+ if (wlan_bg_scan_type_is_passive(pmpriv, channel)) {
+ scan_type = MLAN_SCAN_TYPE_PASSIVE;
+ }
+ }
if (scan_type == MLAN_SCAN_TYPE_PASSIVE) {
(pscan_chan_list + chan_idx)->chan_scan_mode.passive_scan =
MTRUE;
@@ -2938,7 +2945,8 @@ wlan_ret_802_11_scan(IN mlan_private * pmpriv,
pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle,
&pmadapter->age_in_secs,
&age_ts_usec);
-
+ if (is_bgscan_resp)
+ goto done;
if (!util_peek_list
(pmadapter->pmoal_handle, &pmadapter->scan_pending_q,
pcb->moal_spin_lock, pcb->moal_spin_unlock)) {
@@ -2961,6 +2969,7 @@ wlan_ret_802_11_scan(IN mlan_private * pmpriv,
(pmlan_ioctl_req) pioctl_buf,
MLAN_STATUS_SUCCESS);
}
+ pmadapter->bgscan_reported = MFALSE;
wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_SCAN_REPORT, MNULL);
} else {
/* If firmware not ready, do not issue any more scan commands */
@@ -3360,6 +3369,7 @@ wlan_handle_event_ext_scan_report(IN mlan_private * pmpriv,
(pmlan_ioctl_req) pioctl_req,
MLAN_STATUS_SUCCESS);
}
+ pmadapter->bgscan_reported = MFALSE;
wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_SCAN_REPORT, MNULL);
} else {
/* If firmware not ready, do not issue any more scan commands */
@@ -3508,6 +3518,8 @@ wlan_bgscan_create_channel_list(IN mlan_private * pmpriv,
break;
case BAND_B:
case BAND_G:
+ if (wlan_bg_scan_type_is_passive(pmpriv, (t_u8) cfp->channel))
+ scan_type = MLAN_SCAN_TYPE_PASSIVE;
default:
tlv_chan_list->chan_scan_param[chan_idx].radio_type =
HostCmd_SCAN_RADIO_TYPE_BG;
@@ -3575,6 +3587,8 @@ wlan_cmd_bgscan_config(IN mlan_private * pmpriv,
MrvlIEtypes_BeaconLowSnrThreshold_t *snr_tlv = MNULL;
MrvlIEtypes_WildCardSsIdParamSet_t *pwildcard_ssid_tlv = MNULL;
MrvlIEtypes_ChanListParamSet_t *tlv_chan_list = MNULL;
+ MrvlIEtypes_StartLater_t *tlv_start_later = MNULL;
+ MrvlIEtypes_RepeatCount_t *tlv_repeat = MNULL;
t_u8 *tlv = MNULL;
t_u16 num_probes = 0;
t_u32 ssid_idx;
@@ -3640,6 +3654,16 @@ wlan_cmd_bgscan_config(IN mlan_private * pmpriv,
tlv += sizeof(MrvlIEtypes_BeaconLowRssiThreshold_t);
cmd_size += sizeof(MrvlIEtypes_BeaconLowRssiThreshold_t);
}
+ if (bg_scan_in->repeat_count) {
+ tlv_repeat = (MrvlIEtypes_RepeatCount_t *) tlv;
+ tlv_repeat->header.type = wlan_cpu_to_le16(TLV_TYPE_REPEAT_COUNT);
+ tlv_repeat->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_RepeatCount_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ tlv_repeat->repeat_count = wlan_cpu_to_le16(bg_scan_in->repeat_count);
+ tlv += sizeof(MrvlIEtypes_RepeatCount_t);
+ cmd_size += sizeof(MrvlIEtypes_RepeatCount_t);
+ }
for (ssid_idx = 0; ((ssid_idx < NELEMENTS(bg_scan_in->ssid_list))
&& (*bg_scan_in->ssid_list[ssid_idx].ssid ||
bg_scan_in->ssid_list[ssid_idx].max_len));
@@ -3683,6 +3707,12 @@ wlan_cmd_bgscan_config(IN mlan_private * pmpriv,
scan_type = MLAN_SCAN_TYPE_PASSIVE;
}
}
+ if (radio_type == HostCmd_SCAN_RADIO_TYPE_BG) {
+ if (wlan_bg_scan_type_is_passive
+ (pmpriv, bg_scan_in->chan_list[chan_idx].chan_number)) {
+ scan_type = MLAN_SCAN_TYPE_PASSIVE;
+ }
+ }
tlv_chan_list->chan_scan_param[chan_num].chan_number =
bg_scan_in->chan_list[chan_idx].chan_number;
tlv_chan_list->chan_scan_param[chan_num].radio_type =
@@ -3729,6 +3759,14 @@ wlan_cmd_bgscan_config(IN mlan_private * pmpriv,
cmd_size +=
sizeof(MrvlIEtypesHeader_t) + sizeof(ChanScanParamSet_t) * chan_num;
}
+ tlv_start_later = (MrvlIEtypes_StartLater_t *) tlv;
+ tlv_start_later->header.type = wlan_cpu_to_le16(TLV_TYPE_STARTBGSCANLATER);
+ tlv_start_later->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_StartLater_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ tlv_start_later->value = 0;
+ tlv += sizeof(MrvlIEtypes_StartLater_t);
+ cmd_size += sizeof(MrvlIEtypes_StartLater_t);
done:
pcmd->size = wlan_cpu_to_le16(cmd_size);
LEAVE();
@@ -3776,6 +3814,36 @@ wlan_ret_bgscan_config(IN mlan_private * pmpriv,
}
/**
+ * @brief This function handles the command response of bgscan_query
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ret_802_11_bgscan_query(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_scan *pscan = MNULL;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ ENTER();
+ wlan_ret_802_11_scan(pmpriv, resp, MNULL);
+ if (pioctl_buf) {
+ pscan = (mlan_ds_scan *) pioctl_buf->pbuf;
+ pscan->param.scan_resp.pscan_table = (t_u8 *) pmadapter->pscan_table;
+ pscan->param.scan_resp.num_in_scan_table = pmadapter->num_in_scan_table;
+ pscan->param.scan_resp.age_in_secs = pmadapter->age_in_secs;
+ pioctl_buf->data_read_written = sizeof(mlan_scan_resp) +
+ MLAN_SUB_COMMAND_SIZE;
+
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
* @brief This function finds ssid in ssid list.
*
* @param pmpriv A pointer to mlan_private structure
@@ -3812,7 +3880,7 @@ wlan_find_ssid_in_list(IN mlan_private * pmpriv,
MLAN_MAC_ADDR_LENGTH))) {
if (((mode == MLAN_BSS_MODE_INFRA) &&
- !wlan_is_band_compatible(pmadapter->config_bands,
+ !wlan_is_band_compatible(pmpriv->config_bands,
pmadapter->pscan_table[i].bss_band))
||
(wlan_find_cfp_by_band_and_channel
@@ -3896,7 +3964,7 @@ wlan_find_bssid_in_list(IN mlan_private * pmpriv,
(pmadapter, pmadapter->pscan_table[i].mac_address, bssid,
MLAN_MAC_ADDR_LENGTH)) {
if (((mode == MLAN_BSS_MODE_INFRA) &&
- !wlan_is_band_compatible(pmadapter->config_bands,
+ !wlan_is_band_compatible(pmpriv->config_bands,
pmadapter->pscan_table[i].bss_band))
||
(wlan_find_cfp_by_band_and_channel
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_sdio.c b/drivers/net/wireless/sd8797/mlan/mlan_sdio.c
index 0718cec12ee2..02e73477b619 100644
--- a/drivers/net/wireless/sd8797/mlan/mlan_sdio.c
+++ b/drivers/net/wireless/sd8797/mlan/mlan_sdio.c
@@ -218,8 +218,9 @@ wlan_get_wr_port_data(mlan_adapter * pmadapter, t_u8 * pport)
PRINTM(MIF_D, "wlan_get_wr_port_data: mp_wr_bitmap=0x%08x\n", wr_bitmap);
if (!(wr_bitmap & pmadapter->mp_data_port_mask)) {
+ pmadapter->data_sent = MTRUE;
LEAVE();
- return MLAN_STATUS_FAILURE;
+ return MLAN_STATUS_RESOURCE;
}
if (pmadapter->mp_wr_bitmap & (1 << pmadapter->curr_wr_port)) {
@@ -1431,7 +1432,6 @@ wlan_sdio_host_to_card(mlan_adapter * pmadapter, t_u8 type, mlan_buffer * pmbuf,
ret = wlan_get_wr_port_data(pmadapter, &port);
if (ret != MLAN_STATUS_SUCCESS) {
PRINTM(MERROR, "no wr_port available: %d\n", ret);
- pmbuf->status_code = MLAN_ERROR_PKT_INVALID;
goto exit;
}
/* Transfer data to card */
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_shim.c b/drivers/net/wireless/sd8797/mlan/mlan_shim.c
index 1e06a52b87cb..07f7db5c7227 100644
--- a/drivers/net/wireless/sd8797/mlan/mlan_shim.c
+++ b/drivers/net/wireless/sd8797/mlan/mlan_shim.c
@@ -108,6 +108,12 @@ t_void(*assert_callback) (IN t_void * pmoal_handle, IN t_u32 cond) = MNULL;
/** Global moal_print callback */
t_void(*print_callback) (IN t_void * pmoal_handle,
IN t_u32 level, IN t_s8 * pformat, IN ...) = MNULL;
+
+/** Global moal_get_system_time callback */
+mlan_status(*get_sys_time_callback) (IN t_void * pmoal_handle,
+ OUT t_u32 * psec,
+ OUT t_u32 * pusec) = MNULL;
+
/** Global driver debug mit masks */
t_u32 drvdbg = DEFAULT_DEBUG_MASK;
#endif
@@ -161,6 +167,7 @@ mlan_register(IN pmlan_device pmdevice, OUT t_void ** ppmlan_adapter)
MASSERT(pmdevice->callbacks.moal_print);
#ifdef DEBUG_LEVEL1
print_callback = pmdevice->callbacks.moal_print;
+ get_sys_time_callback = pmdevice->callbacks.moal_get_system_time;
#endif
assert_callback = pmdevice->callbacks.moal_assert;
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_sta_cmd.c b/drivers/net/wireless/sd8797/mlan/mlan_sta_cmd.c
index c91fcc9f6e12..7c426595117e 100644
--- a/drivers/net/wireless/sd8797/mlan/mlan_sta_cmd.c
+++ b/drivers/net/wireless/sd8797/mlan/mlan_sta_cmd.c
@@ -151,6 +151,16 @@ wlan_cmd_802_11_snmp_mib(IN pmlan_private pmpriv,
}
switch (cmd_oid) {
+ case DtimPeriod_i:
+ psnmp_mib->oid = wlan_cpu_to_le16((t_u16) DtimPeriod_i);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ psnmp_mib->query_type = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(sizeof(t_u8));
+ ul_temp = *((t_u32 *) pdata_buf);
+ psnmp_mib->value[0] = (t_u8) ul_temp;
+ cmd->size += sizeof(t_u8);
+ }
+ break;
case FragThresh_i:
psnmp_mib->oid = wlan_cpu_to_le16((t_u16) FragThresh_i);
if (cmd_action == HostCmd_ACT_GEN_SET) {
@@ -712,7 +722,22 @@ wlan_cmd_802_11_key_material(IN pmlan_private pmpriv,
pkey_material->action = wlan_cpu_to_le16(cmd_action);
if (cmd_action == HostCmd_ACT_GEN_GET) {
- cmd->size = wlan_cpu_to_le16(sizeof(pkey_material->action) + S_DS_GEN);
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(pkey_material->action) + S_DS_GEN +
+ KEYPARAMSET_FIXED_LEN +
+ sizeof(MrvlIEtypesHeader_t));
+ memset(pmpriv->adapter, &pkey_material->key_param_set, 0,
+ sizeof(MrvlIEtype_KeyParamSet_t));
+ pkey_material->key_param_set.type =
+ wlan_cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+ pkey_material->key_param_set.length =
+ wlan_cpu_to_le16(KEYPARAMSET_FIXED_LEN);
+ if (pkey->key_flags & KEY_FLAG_GROUP_KEY)
+ pkey_material->key_param_set.key_info |= KEY_INFO_MCAST_KEY;
+ else
+ pkey_material->key_param_set.key_info |= KEY_INFO_UCAST_KEY;
+ pkey_material->key_param_set.key_info =
+ wlan_cpu_to_le16(pkey_material->key_param_set.key_info);
goto done;
}
@@ -963,10 +988,14 @@ wlan_cmd_802_11_supplicant_pmk(IN pmlan_private pmpriv,
static mlan_status
wlan_cmd_802_11_supplicant_profile(IN pmlan_private pmpriv,
IN HostCmd_DS_COMMAND * cmd,
- IN t_u16 cmd_action)
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
{
HostCmd_DS_802_11_SUPPLICANT_PROFILE *sup_profile =
&cmd->params.esupplicant_profile;
+ MrvlIEtypes_EncrProto_t *encr_proto_tlv = MNULL;
+ MrvlIEtypes_Cipher_t *pcipher_tlv = MNULL;
+ t_u8 *ptlv_buffer = (t_u8 *) sup_profile->tlv_buf;
+ mlan_ds_esupp_mode *esupp = MNULL;
ENTER();
@@ -975,6 +1004,44 @@ wlan_cmd_802_11_supplicant_profile(IN pmlan_private pmpriv,
S_DS_GEN - 1);
cmd->command = wlan_cpu_to_le16(HostCmd_CMD_SUPPLICANT_PROFILE);
sup_profile->action = wlan_cpu_to_le16(cmd_action);
+ if ((cmd_action == HostCmd_ACT_GEN_SET) && pdata_buf) {
+ esupp = (mlan_ds_esupp_mode *) pdata_buf;
+ if (esupp->rsn_mode) {
+ encr_proto_tlv = (MrvlIEtypes_EncrProto_t *) ptlv_buffer;
+ encr_proto_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_ENCRYPTION_PROTO);
+ encr_proto_tlv->header.len =
+ (t_u16) sizeof(encr_proto_tlv->rsn_mode);
+ encr_proto_tlv->rsn_mode = wlan_cpu_to_le16(esupp->rsn_mode);
+ ptlv_buffer +=
+ (encr_proto_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ cmd->size +=
+ (encr_proto_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ encr_proto_tlv->header.len =
+ wlan_cpu_to_le16(encr_proto_tlv->header.len);
+ }
+ if (esupp->act_paircipher || esupp->act_groupcipher) {
+ pcipher_tlv = (MrvlIEtypes_Cipher_t *) ptlv_buffer;
+ pcipher_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_CIPHER);
+ pcipher_tlv->header.len =
+ (t_u16) (sizeof(pcipher_tlv->pair_cipher) +
+ sizeof(pcipher_tlv->group_cipher));
+ if (esupp->act_paircipher) {
+ pcipher_tlv->pair_cipher =
+ wlan_cpu_to_le16(esupp->act_paircipher);
+ }
+ if (esupp->act_groupcipher) {
+ pcipher_tlv->group_cipher =
+ wlan_cpu_to_le16(esupp->act_groupcipher);
+ }
+ ptlv_buffer +=
+ (pcipher_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ cmd->size +=
+ (pcipher_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ pcipher_tlv->header.len = wlan_cpu_to_le16(pcipher_tlv->header.len);
+ }
+ }
+ cmd->size = wlan_cpu_to_le16(cmd->size);
LEAVE();
return MLAN_STATUS_SUCCESS;
}
@@ -1113,7 +1180,8 @@ wlan_cmd_mgmt_ie_list(IN pmlan_private pmpriv,
}
cmd->size -=
- (MAX_MGMT_IE_INDEX * sizeof(custom_ie)) + sizeof(tlvbuf_max_mgmt_ie);
+ (MAX_MGMT_IE_INDEX_TO_FW * sizeof(custom_ie)) +
+ sizeof(tlvbuf_max_mgmt_ie);
cmd->size += cust_ie->len;
cmd->size = wlan_cpu_to_le16(cmd->size);
@@ -1460,6 +1528,42 @@ wlan_cmd_subscribe_event(IN pmlan_private pmpriv,
}
/**
+ * @brief This function prepares command of OTP user data.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_otp_user_data(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ mlan_ds_misc_otp_user_data *user_data =
+ (mlan_ds_misc_otp_user_data *) pdata_buf;
+ HostCmd_DS_OTP_USER_DATA *cmd_user_data =
+ (HostCmd_DS_OTP_USER_DATA *) & cmd->params.otp_user_data;
+ t_u16 cmd_size = 0;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_OTP_READ_USER_DATA);
+ cmd_size = sizeof(HostCmd_DS_OTP_USER_DATA) + S_DS_GEN - 1;
+
+ cmd_user_data->action = wlan_cpu_to_le16(cmd_action);
+ cmd_user_data->reserved = 0;
+ cmd_user_data->user_data_length =
+ wlan_cpu_to_le16(user_data->user_data_length);
+ cmd_size += user_data->user_data_length;
+ cmd->size = wlan_cpu_to_le16(cmd_size);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
* @brief This function prepares inactivity timeout command
*
* @param cmd A pointer to HostCmd_DS_COMMAND structure
@@ -1679,7 +1783,8 @@ wlan_ops_sta_prepare_cmd(IN t_void * priv,
pdata_buf);
break;
case HostCmd_CMD_SUPPLICANT_PROFILE:
- ret = wlan_cmd_802_11_supplicant_profile(pmpriv, cmd_ptr, cmd_action);
+ ret = wlan_cmd_802_11_supplicant_profile(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
break;
case HostCmd_CMD_802_11D_DOMAIN_INFO:
@@ -1786,6 +1891,9 @@ wlan_ops_sta_prepare_cmd(IN t_void * priv,
case HostCmd_CMD_802_11_SUBSCRIBE_EVENT:
ret = wlan_cmd_subscribe_event(pmpriv, cmd_ptr, cmd_action, pdata_buf);
break;
+ case HostCmd_CMD_OTP_READ_USER_DATA:
+ ret = wlan_cmd_otp_user_data(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
default:
PRINTM(MERROR, "PREP_CMD: unknown command- %#x\n", cmd_no);
ret = MLAN_STATUS_FAILURE;
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_sta_cmdresp.c b/drivers/net/wireless/sd8797/mlan/mlan_sta_cmdresp.c
index be56a16615b9..086d16ae5a62 100644
--- a/drivers/net/wireless/sd8797/mlan/mlan_sta_cmdresp.c
+++ b/drivers/net/wireless/sd8797/mlan/mlan_sta_cmdresp.c
@@ -3,7 +3,7 @@
* @brief This file contains the handling of command
* responses generated by firmware.
*
- * Copyright (C) 2008-2011, Marvell International Ltd.
+ * Copyright (C) 2008-2012, Marvell International Ltd.
*
* This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
@@ -231,6 +231,12 @@ wlan_ret_802_11_snmp_mib(IN pmlan_private pmpriv,
wlan_le16_to_cpu(psmib->buf_size));
if (query_type == HostCmd_ACT_GEN_GET) {
switch (oid) {
+ case DtimPeriod_i:
+ ul_temp = psmib->value[0];
+ PRINTM(MINFO, "SNMP_RESP: DTIM Period =%u\n", ul_temp);
+ if (mib)
+ mib->param.dtim_period = ul_temp;
+ break;
case FragThresh_i:
ul_temp = wlan_le16_to_cpu(*((t_u16 *) (psmib->value)));
PRINTM(MINFO, "SNMP_RESP: FragThsd =%u\n", ul_temp);
@@ -765,6 +771,7 @@ wlan_ret_802_11_key_material(IN pmlan_private pmpriv,
IN mlan_ioctl_req * pioctl_buf)
{
HostCmd_DS_802_11_KEY_MATERIAL *pkey = &resp->params.key_material;
+ mlan_ds_sec_cfg *sec = MNULL;
ENTER();
@@ -780,8 +787,50 @@ wlan_ret_802_11_key_material(IN pmlan_private pmpriv,
}
pmpriv->scan_block = MFALSE;
}
+ } else {
+ if (pioctl_buf &&
+ (wlan_le16_to_cpu(pkey->key_param_set.type) ==
+ TLV_TYPE_KEY_MATERIAL)) {
+ PRINTM(MIOCTL, "key_type_id=%d, key_len=%d, key_info=0x%x\n",
+ wlan_le16_to_cpu(pkey->key_param_set.key_type_id),
+ wlan_le16_to_cpu(pkey->key_param_set.key_len),
+ wlan_le16_to_cpu(pkey->key_param_set.key_info));
+ sec = (mlan_ds_sec_cfg *) pioctl_buf->pbuf;
+#define WAPI_KEY_SIZE 32
+ switch (wlan_le16_to_cpu(pkey->key_param_set.key_type_id)) {
+ case KEY_TYPE_ID_WEP:
+ sec->param.encrypt_key.key_index = pkey->key_param_set.key[0];
+ sec->param.encrypt_key.key_len =
+ wlan_le16_to_cpu(pkey->key_param_set.key_len);
+ memcpy(pmpriv->adapter, sec->param.encrypt_key.key_material,
+ &pkey->key_param_set.key[2],
+ sec->param.encrypt_key.key_len);
+ break;
+ case KEY_TYPE_ID_TKIP:
+ sec->param.encrypt_key.key_len =
+ wlan_le16_to_cpu(pkey->key_param_set.key_len);
+ memcpy(pmpriv->adapter, sec->param.encrypt_key.key_material,
+ pkey->key_param_set.key, sec->param.encrypt_key.key_len);
+ break;
+ case KEY_TYPE_ID_AES:
+ sec->param.encrypt_key.key_len =
+ wlan_le16_to_cpu(pkey->key_param_set.key_len);
+ memcpy(pmpriv->adapter, sec->param.encrypt_key.key_material,
+ pkey->key_param_set.key, sec->param.encrypt_key.key_len);
+ break;
+ case KEY_TYPE_ID_WAPI:
+ sec->param.encrypt_key.is_wapi_key = MTRUE;
+ sec->param.encrypt_key.key_index = pkey->key_param_set.key[0];
+ sec->param.encrypt_key.key_len = WAPI_KEY_SIZE;
+ memcpy(pmpriv->adapter, sec->param.encrypt_key.key_material,
+ &pkey->key_param_set.key[2],
+ sec->param.encrypt_key.key_len);
+ memcpy(pmpriv->adapter, sec->param.encrypt_key.pn,
+ &pkey->key_param_set.key[2 + WAPI_KEY_SIZE], PN_SIZE);
+ break;
+ }
+ }
}
-
LEAVE();
return MLAN_STATUS_SUCCESS;
}
@@ -1374,6 +1423,41 @@ wlan_ret_subscribe_event(IN pmlan_private pmpriv,
return MLAN_STATUS_SUCCESS;
}
+/**
+ * @brief This function handles the command response of
+ * OTP user data
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to command buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_otp_user_data(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+
+ HostCmd_DS_OTP_USER_DATA *cmd_user_data =
+ (HostCmd_DS_OTP_USER_DATA *) & resp->params.otp_user_data;
+ mlan_ds_misc_otp_user_data *user_data = MNULL;
+
+ ENTER();
+ if (pioctl_buf && (pioctl_buf->action == MLAN_ACT_GET)) {
+ user_data = (mlan_ds_misc_otp_user_data *) pioctl_buf->pbuf;
+ user_data->user_data_length = MIN(MAX_OTP_USER_DATA_LEN,
+ wlan_le16_to_cpu(cmd_user_data->
+ user_data_length));
+ memcpy(pmpriv->adapter, user_data->user_data, cmd_user_data->user_data,
+ user_data->user_data_length);
+ pioctl_buf->data_read_written =
+ sizeof(mlan_ds_misc_otp_user_data) + user_data->user_data_length;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
/********************************************************
Global Functions
********************************************************/
@@ -1442,8 +1526,7 @@ wlan_ops_sta_process_cmdresp(IN t_void * priv,
ret = wlan_ret_bgscan_config(pmpriv, resp, pioctl_buf);
break;
case HostCmd_CMD_802_11_BG_SCAN_QUERY:
- ret = wlan_ret_802_11_scan(pmpriv, resp, pioctl_buf);
- wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BG_SCAN, MNULL);
+ ret = wlan_ret_802_11_bgscan_query(pmpriv, resp, pioctl_buf);
PRINTM(MINFO, "CMD_RESP: BG_SCAN result is ready!\n");
break;
case HostCmd_CMD_TXPWR_CFG:
@@ -1629,6 +1712,9 @@ wlan_ops_sta_process_cmdresp(IN t_void * priv,
case HostCmd_CMD_802_11_SUBSCRIBE_EVENT:
ret = wlan_ret_subscribe_event(pmpriv, resp, pioctl_buf);
break;
+ case HostCmd_CMD_OTP_READ_USER_DATA:
+ ret = wlan_ret_otp_user_data(pmpriv, resp, pioctl_buf);
+ break;
default:
PRINTM(MERROR, "CMD_RESP: Unknown command response %#x\n",
resp->command);
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_sta_event.c b/drivers/net/wireless/sd8797/mlan/mlan_sta_event.c
index f638241f9632..1ad77818995f 100644
--- a/drivers/net/wireless/sd8797/mlan/mlan_sta_event.c
+++ b/drivers/net/wireless/sd8797/mlan/mlan_sta_event.c
@@ -341,14 +341,8 @@ wlan_ops_sta_process_event(IN t_void * priv)
case EVENT_BG_SCAN_REPORT:
PRINTM(MEVENT, "EVENT: BGS_REPORT\n");
- /* Clear the previous scan result */
- memset(pmadapter, pmadapter->pscan_table, 0x00,
- sizeof(BSSDescriptor_t) * MRVDRV_MAX_BSSID_LIST);
- pmadapter->num_in_scan_table = 0;
- pmadapter->pbcn_buf_end = pmadapter->bcn_buf;
- ret = wlan_prepare_cmd(pmpriv,
- HostCmd_CMD_802_11_BG_SCAN_QUERY,
- HostCmd_ACT_GEN_GET, 0, MNULL, MNULL);
+ pmadapter->bgscan_reported = MTRUE;
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BG_SCAN, MNULL);
break;
case EVENT_PORT_RELEASE:
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_sta_ioctl.c b/drivers/net/wireless/sd8797/mlan/mlan_sta_ioctl.c
index 72dd525ca4af..eb715cb804c8 100644
--- a/drivers/net/wireless/sd8797/mlan/mlan_sta_ioctl.c
+++ b/drivers/net/wireless/sd8797/mlan/mlan_sta_ioctl.c
@@ -222,6 +222,9 @@ wlan_get_info_bss_info(IN pmlan_adapter pmadapter,
/* Channel */
info->param.bss_info.bss_chan = pbss_desc->channel;
+ /* Beacon interval */
+ info->param.bss_info.beacon_interval = pbss_desc->beacon_period;
+
/* Band */
info->param.bss_info.bss_band = (t_u8) pbss_desc->bss_band;
@@ -396,6 +399,10 @@ wlan_snmp_mib_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
value = mib->param.retry_count;
cmd_oid = ShortRetryLim_i;
break;
+ case MLAN_OID_SNMP_MIB_DTIM_PERIOD:
+ value = mib->param.dtim_period;
+ cmd_oid = DtimPeriod_i;
+ break;
}
/* Send request to firmware */
@@ -509,6 +516,7 @@ wlan_radio_ioctl_band_cfg(IN pmlan_adapter pmadapter,
}
pmpriv->adhoc_channel = (t_u8) adhoc_channel;
}
+
if ((adhoc_band & BAND_GN)
|| (adhoc_band & BAND_AN)
) {
@@ -993,6 +1001,7 @@ wlan_bss_ioctl_start(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
CLOSED state */
if (pmpriv->port_ctrl_mode == MTRUE) {
PRINTM(MINFO, "bss_ioctl_start(): port_state=CLOSED\n");
+ pmpriv->prior_port_status = pmpriv->port_open;
pmpriv->port_open = MFALSE;
}
pmpriv->scan_block = MFALSE;
@@ -1437,7 +1446,7 @@ wlan_rate_ioctl_get_supported_rate(IN pmlan_adapter pmadapter,
else
wlan_get_active_data_rates(pmpriv, pmpriv->bss_mode,
(pmpriv->bss_mode == MLAN_BSS_MODE_INFRA) ?
- pmadapter->config_bands : pmadapter->
+ pmpriv->config_bands : pmadapter->
adhoc_start_band, rate->param.rates);
pioctl_req->data_read_written =
MLAN_SUPPORTED_RATES + MLAN_SUB_COMMAND_SIZE;
@@ -3306,20 +3315,61 @@ wlan_sec_ioctl_esupp_mode(IN pmlan_adapter pmadapter,
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ t_u16 cmd_action = 0;
+ mlan_ds_sec_cfg *sec = MNULL;
ENTER();
- if (pmpriv->media_connected != MTRUE) {
- pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
- ret = MLAN_STATUS_FAILURE;
- goto exit;
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ cmd_action = HostCmd_ACT_GEN_SET;
+ if (pmpriv->media_connected == MTRUE) {
+ PRINTM(MERROR,
+ "Cannot set esupplicant mode configuration while connected.\n");
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ if (!sec->param.esupp_mode.rsn_mode ||
+ (sec->param.esupp_mode.rsn_mode & RSN_TYPE_VALID_BITS)
+ != sec->param.esupp_mode.rsn_mode) {
+ PRINTM(MERROR, "Invalid RSN mode\n");
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ if (!sec->param.esupp_mode.act_paircipher ||
+ (sec->param.esupp_mode.act_paircipher & EMBED_CIPHER_VALID_BITS)
+ != sec->param.esupp_mode.act_paircipher) {
+ PRINTM(MERROR, "Invalid pairwise cipher\n");
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ if (!sec->param.esupp_mode.act_groupcipher ||
+ (sec->param.esupp_mode.act_groupcipher & EMBED_CIPHER_VALID_BITS)
+ != sec->param.esupp_mode.act_groupcipher) {
+ PRINTM(MERROR, "Invalid group cipher\n");
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ } else {
+ cmd_action = HostCmd_ACT_GEN_GET_CURRENT;
}
/* Send request to firmware */
- ret = wlan_prepare_cmd(pmpriv,
- HostCmd_CMD_SUPPLICANT_PROFILE,
- HostCmd_ACT_GEN_GET_CURRENT,
- 0, (t_void *) pioctl_req, MNULL);
+ if (sec) {
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_SUPPLICANT_PROFILE,
+ cmd_action,
+ 0,
+ (t_void *) pioctl_req, &sec->param.esupp_mode);
+ } else {
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_SUPPLICANT_PROFILE,
+ cmd_action, 0, (t_void *) pioctl_req, MNULL);
+ }
if (ret == MLAN_STATUS_SUCCESS)
ret = MLAN_STATUS_PENDING;
@@ -4137,6 +4187,8 @@ wlan_misc_ioctl_region(IN pmlan_adapter pmadapter,
LEAVE();
return MLAN_STATUS_FAILURE;
}
+ pmadapter->cfp_code_bg = misc->param.region_code;
+ pmadapter->cfp_code_a = misc->param.region_code;
if (wlan_set_regiontable(pmpriv, (t_u8) pmadapter->region_code,
pmadapter->config_bands | pmadapter->
adhoc_start_band)) {
@@ -4827,6 +4879,158 @@ wlan_misc_ioctl_ipaddr_cfg(IN pmlan_adapter pmadapter,
}
/**
+ * @brief CFP code configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status
+wlan_misc_ioctl_cfp_code_cfg(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ mlan_ds_misc_cfp_code *cfp_code = MNULL;
+ t_u32 region_bg = 0;
+ t_u32 region_a = 0;
+ int i;
+
+ ENTER();
+
+ cfp_code = &misc->param.cfp_code;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ /* Save the values in MLAN */
+ if (!cfp_code->cfp_code_bg)
+ cfp_code->cfp_code_bg = pmadapter->cfp_code_bg;
+ for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
+ /* Use the region code to search for the index */
+ if (cfp_code->cfp_code_bg == region_code_index[i]) {
+ region_bg = cfp_code->cfp_code_bg;
+ break;
+ }
+ }
+ if (!region_bg) {
+ for (i = 0; i < MRVDRV_MAX_CFP_CODE_BG; i++) {
+ /* Use the CFP code to search for the index */
+ if (cfp_code->cfp_code_bg == cfp_code_index_bg[i])
+ break;
+ }
+ if (i >= MRVDRV_MAX_CFP_CODE_BG) {
+ PRINTM(MERROR, "CFP Code not identified for BG\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+ if (!cfp_code->cfp_code_a)
+ cfp_code->cfp_code_a = pmadapter->cfp_code_a;
+ for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
+ /* Use the region code to search for the index */
+ if (cfp_code->cfp_code_a == region_code_index[i]) {
+ region_a = cfp_code->cfp_code_a;
+ break;
+ }
+ }
+ if (!region_a) {
+ for (i = 0; i < MRVDRV_MAX_CFP_CODE_A; i++) {
+ /* Use the CFP code to search for the index */
+ if (cfp_code->cfp_code_a == cfp_code_index_a[i])
+ break;
+ }
+ if (i >= MRVDRV_MAX_CFP_CODE_A) {
+ PRINTM(MERROR, "CFP Code not identified for A\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+ pmadapter->cfp_code_bg = (t_u8) cfp_code->cfp_code_bg;
+ pmadapter->cfp_code_a = (t_u8) cfp_code->cfp_code_a;
+ if (region_bg && region_a && (region_bg == region_a))
+ pmadapter->region_code = pmadapter->cfp_code_a;
+ else
+ pmadapter->region_code = 0;
+ if (wlan_set_regiontable(pmpriv, (t_u8) pmadapter->region_code,
+ pmadapter->config_bands | pmadapter->
+ adhoc_start_band)) {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ } else {
+ /* GET operation */
+ cfp_code->cfp_code_bg = pmadapter->cfp_code_bg;
+ cfp_code->cfp_code_a = pmadapter->cfp_code_a;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function sets up country code and downloads CMD to FW
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req Pointer to the IOCTL request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_misc_ioctl_country_code(IN pmlan_adapter pmadapter,
+ IN mlan_ioctl_req * pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_country_code *country_code = MNULL;
+ mlan_ds_misc_cfg *cfg_misc = MNULL;
+ t_u8 cfp_bg = 0, cfp_a = 0;
+
+ ENTER();
+
+ cfg_misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ country_code = &cfg_misc->param.country_code;
+
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ /* Update region code and table based on country code */
+ if (wlan_misc_country_2_cfp_table_code(pmadapter,
+ country_code->country_code,
+ &cfp_bg, &cfp_a)) {
+ PRINTM(MERROR, "Country code not found!\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ pmadapter->cfp_code_bg = cfp_bg;
+ pmadapter->cfp_code_a = cfp_a;
+ if (cfp_bg && cfp_a && (cfp_bg == cfp_a))
+ pmadapter->region_code = cfp_a;
+ else
+ pmadapter->region_code = 0;
+ if (wlan_set_regiontable(pmpriv, pmadapter->region_code,
+ pmadapter->config_bands | pmadapter->
+ adhoc_start_band)) {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ memcpy(pmadapter, pmadapter->country_code,
+ country_code->country_code, COUNTRY_CODE_LEN);
+ } else {
+ /* GET operation */
+ memcpy(pmadapter, country_code->country_code,
+ pmadapter->country_code, COUNTRY_CODE_LEN);
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
* @brief Miscellaneous configuration handler
*
* @param pmadapter A pointer to mlan_adapter structure
@@ -4906,12 +5110,21 @@ wlan_misc_cfg_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
case MLAN_OID_MISC_IP_ADDR:
status = wlan_misc_ioctl_ipaddr_cfg(pmadapter, pioctl_req);
break;
+ case MLAN_OID_MISC_CFP_CODE:
+ status = wlan_misc_ioctl_cfp_code_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_COUNTRY_CODE:
+ status = wlan_misc_ioctl_country_code(pmadapter, pioctl_req);
+ break;
case MLAN_OID_MISC_THERMAL:
status = wlan_misc_ioctl_thermal(pmadapter, pioctl_req);
break;
case MLAN_OID_MISC_SUBSCRIBE_EVENT:
status = wlan_misc_ioctl_subscribe_evt(pmadapter, pioctl_req);
break;
+ case MLAN_OID_MISC_OTP_USER_DATA:
+ status = wlan_misc_otp_user_data(pmadapter, pioctl_req);
+ break;
default:
if (pioctl_req)
pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
@@ -5070,13 +5283,31 @@ wlan_scan_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
pioctl_req->data_read_written =
sizeof(mlan_scan_resp) + MLAN_SUB_COMMAND_SIZE;
} else {
- pscan->param.scan_resp.pscan_table =
- (t_u8 *) pmadapter->pscan_table;
- pscan->param.scan_resp.num_in_scan_table =
- pmadapter->num_in_scan_table;
- pscan->param.scan_resp.age_in_secs = pmadapter->age_in_secs;
- pioctl_req->data_read_written = sizeof(mlan_scan_resp) +
- MLAN_SUB_COMMAND_SIZE;
+ if (pmadapter->bgscan_reported) {
+ pmadapter->bgscan_reported = MFALSE;
+ /* Clear the previous scan result */
+ memset(pmadapter, pmadapter->pscan_table, 0x00,
+ sizeof(BSSDescriptor_t) * MRVDRV_MAX_BSSID_LIST);
+ pmadapter->num_in_scan_table = 0;
+ pmadapter->pbcn_buf_end = pmadapter->bcn_buf;
+ status = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_BG_SCAN_QUERY,
+ HostCmd_ACT_GEN_GET,
+ 0, (t_void *) pioctl_req, MNULL);
+ if (status == MLAN_STATUS_SUCCESS) {
+ PRINTM(MINFO,
+ "wlan_scan_ioctl: return MLAN_STATUS_PENDING\n");
+ status = MLAN_STATUS_PENDING;
+ }
+ } else {
+ pscan->param.scan_resp.pscan_table =
+ (t_u8 *) pmadapter->pscan_table;
+ pscan->param.scan_resp.num_in_scan_table =
+ pmadapter->num_in_scan_table;
+ pscan->param.scan_resp.age_in_secs = pmadapter->age_in_secs;
+ pioctl_req->data_read_written = sizeof(mlan_scan_resp) +
+ MLAN_SUB_COMMAND_SIZE;
+ }
}
}
@@ -5198,6 +5429,7 @@ wlan_ops_sta_ioctl(t_void * adapter, pmlan_ioctl_req pioctl_req)
mlan_status status = MLAN_STATUS_SUCCESS;
ENTER();
+
switch (pioctl_req->req_id) {
case MLAN_IOCTL_SCAN:
status = wlan_scan_ioctl(pmadapter, pioctl_req);
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_sta_rx.c b/drivers/net/wireless/sd8797/mlan/mlan_sta_rx.c
index 2ad9a810afcf..5e5c68e2a108 100644
--- a/drivers/net/wireless/sd8797/mlan/mlan_sta_rx.c
+++ b/drivers/net/wireless/sd8797/mlan/mlan_sta_rx.c
@@ -2,7 +2,7 @@
*
* @brief This file contains the handling of RX in MLAN
* module.
- *
+ *
* Copyright (C) 2008-2011, Marvell International Ltd.
*
* This software file (the "File") is distributed by Marvell International
@@ -59,6 +59,7 @@ typedef struct
/********************************************************
Global functions
********************************************************/
+
/**
* @brief This function processes received packet and forwards it
* to kernel/upper layer
@@ -174,6 +175,7 @@ wlan_process_rx_packet(pmlan_adapter pmadapter, pmlan_buffer pmbuf)
PRINTM(MDATA, "%lu.%06lu : Data => kernel seq_num=%d tid=%d\n",
pmbuf->out_ts_sec, pmbuf->out_ts_usec, prx_pd->seq_num,
prx_pd->priority);
+
ret = pmadapter->callbacks.moal_recv_packet(pmadapter->pmoal_handle, pmbuf);
if (ret == MLAN_STATUS_FAILURE) {
pmbuf->status_code = MLAN_ERROR_PKT_INVALID;
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_sta_tx.c b/drivers/net/wireless/sd8797/mlan/mlan_sta_tx.c
index 06c1a4de064e..2258853a4089 100644
--- a/drivers/net/wireless/sd8797/mlan/mlan_sta_tx.c
+++ b/drivers/net/wireless/sd8797/mlan/mlan_sta_tx.c
@@ -166,7 +166,9 @@ wlan_send_null_packet(pmlan_private priv, t_u8 flags)
pmlan_buffer pmbuf = MNULL;
t_u8 *ptr;
mlan_status ret = MLAN_STATUS_SUCCESS;
+#ifdef DEBUG_LEVEL1
t_u32 sec, usec;
+#endif
ENTER();
@@ -228,8 +230,7 @@ wlan_send_null_packet(pmlan_private priv, t_u8 flags)
break;
}
- pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle, &sec,
- &usec);
+ PRINTM_GET_SYS_TIME(MDATA, &sec, &usec);
PRINTM(MDATA, "%lu.%06lu : Null data => FW\n", sec, usec);
DBG_HEXDUMP(MDAT_D, "Null data", ptr, sizeof(TxPD) + INTF_HEADER_LEN);
done:
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_txrx.c b/drivers/net/wireless/sd8797/mlan/mlan_txrx.c
index e15dd14f0443..93dea9e284f8 100644
--- a/drivers/net/wireless/sd8797/mlan/mlan_txrx.c
+++ b/drivers/net/wireless/sd8797/mlan/mlan_txrx.c
@@ -63,7 +63,9 @@ wlan_handle_rx_packet(pmlan_adapter pmadapter, pmlan_buffer pmbuf)
mlan_status ret = MLAN_STATUS_SUCCESS;
pmlan_private priv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
RxPD *prx_pd;
+#ifdef DEBUG_LEVEL1
t_u32 sec, usec;
+#endif
ENTER();
@@ -75,8 +77,7 @@ wlan_handle_rx_packet(pmlan_adapter pmadapter, pmlan_buffer pmbuf)
if (!priv)
priv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
pmbuf->bss_index = priv->bss_index;
- pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle, &sec,
- &usec);
+ PRINTM_GET_SYS_TIME(MDATA, &sec, &usec);
PRINTM_NETINTF(MDATA, priv);
PRINTM(MDATA, "%lu.%06lu : Data <= FW\n", sec, usec);
ret = priv->ops.process_rx_packet(pmadapter, pmbuf);
@@ -101,7 +102,9 @@ wlan_process_tx(pmlan_private priv, pmlan_buffer pmbuf,
mlan_status ret = MLAN_STATUS_SUCCESS;
pmlan_adapter pmadapter = priv->adapter;
t_u8 *head_ptr = MNULL;
+#ifdef DEBUG_LEVEL1
t_u32 sec, usec;
+#endif
#ifdef STA_SUPPORT
TxPD *plocal_tx_pd = MNULL;
#endif
@@ -153,8 +156,7 @@ wlan_process_tx(pmlan_private priv, pmlan_buffer pmbuf,
}
if ((ret == MLAN_STATUS_SUCCESS) || (ret == MLAN_STATUS_PENDING)) {
- pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle, &sec,
- &usec);
+ PRINTM_GET_SYS_TIME(MDATA, &sec, &usec);
PRINTM_NETINTF(MDATA, priv);
PRINTM(MDATA, "%lu.%06lu : Data => FW\n", sec, usec);
}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_uap_cmdevent.c b/drivers/net/wireless/sd8797/mlan/mlan_uap_cmdevent.c
index ed79dcfaaf68..7d7d5510433c 100644
--- a/drivers/net/wireless/sd8797/mlan/mlan_uap_cmdevent.c
+++ b/drivers/net/wireless/sd8797/mlan/mlan_uap_cmdevent.c
@@ -3,7 +3,7 @@
* @brief This file contains the handling of AP mode command and event
*
* Copyright (C) 2009-2011, Marvell International Ltd.
- *
+ *
* This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
* (the "License"). You may use, redistribute and/or modify this File in
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_uap_ioctl.c b/drivers/net/wireless/sd8797/mlan/mlan_uap_ioctl.c
index 5081d9e4aabc..f71a222f4f48 100644
--- a/drivers/net/wireless/sd8797/mlan/mlan_uap_ioctl.c
+++ b/drivers/net/wireless/sd8797/mlan/mlan_uap_ioctl.c
@@ -3,7 +3,7 @@
* @brief This file contains the handling of AP mode ioctls
*
* Copyright (C) 2009-2011, Marvell International Ltd.
- *
+ *
* This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
* (the "License"). You may use, redistribute and/or modify this File in
@@ -230,8 +230,8 @@ wlan_uap_bss_ioctl_reset(IN pmlan_adapter pmadapter,
memset(pmadapter, &pmpriv->mgmt_ie[i], 0, sizeof(custom_ie));
}
pmpriv->add_ba_param.timeout = MLAN_DEFAULT_BLOCK_ACK_TIMEOUT;
- pmpriv->add_ba_param.tx_win_size = MLAN_AMPDU_DEF_TXWINSIZE;
- pmpriv->add_ba_param.rx_win_size = MLAN_AMPDU_DEF_RXWINSIZE;
+ pmpriv->add_ba_param.tx_win_size = MLAN_UAP_AMPDU_DEF_TXWINSIZE;
+ pmpriv->add_ba_param.rx_win_size = MLAN_UAP_AMPDU_DEF_RXWINSIZE;
for (i = 0; i < MAX_NUM_TID; i++) {
pmpriv->aggr_prio_tbl[i].ampdu_user = tos_to_tid_inv[i];
pmpriv->aggr_prio_tbl[i].amsdu = BA_STREAM_NOT_ALLOWED;
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_uap_txrx.c b/drivers/net/wireless/sd8797/mlan/mlan_uap_txrx.c
index 0abd1ecd1c2a..590def325f27 100644
--- a/drivers/net/wireless/sd8797/mlan/mlan_uap_txrx.c
+++ b/drivers/net/wireless/sd8797/mlan/mlan_uap_txrx.c
@@ -3,7 +3,7 @@
* @brief This file contains AP mode transmit and receive functions
*
* Copyright (C) 2009-2011, Marvell International Ltd.
- *
+ *
* This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
* (the "License"). You may use, redistribute and/or modify this File in
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_wmm.c b/drivers/net/wireless/sd8797/mlan/mlan_wmm.c
index d2c3227aca87..4b72c9193e27 100644
--- a/drivers/net/wireless/sd8797/mlan/mlan_wmm.c
+++ b/drivers/net/wireless/sd8797/mlan/mlan_wmm.c
@@ -946,8 +946,6 @@ wlan_dequeue_tx_packet(pmlan_adapter pmadapter)
t_u8 ra[MLAN_MAC_ADDR_LENGTH];
int tid_del = 0;
int tid = 0;
- t_u8 avail_ports = 0;
- int i;
ENTER();
@@ -975,24 +973,6 @@ wlan_dequeue_tx_packet(pmlan_adapter pmadapter)
if (tid >= MAX_NUM_TID)
tid = wlan_wmm_downgrade_tid(priv, tid);
- for (i = 1; i < pmadapter->mp_end_port; i++) {
- if ((pmadapter->mp_wr_bitmap >> i) & 1)
- avail_ports++;
- }
-
- PRINTM(MINFO,
- "mp_wr_bitmap=0x%08x avail_ports=%d tid=%d tx_eligibility[%d]=%d\n",
- pmadapter->mp_wr_bitmap, avail_ports,
- tid, tid, pmadapter->tx_eligibility[tid]);
-
- if (avail_ports < pmadapter->tx_eligibility[tid]) {
- pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
- priv->wmm.ra_list_spinlock);
- pmadapter->data_sent = MTRUE;
- LEAVE();
- return MLAN_STATUS_FAILURE;
- }
-
if (wlan_is_ptr_processed(priv, ptr)) {
wlan_send_processed_packet(priv, ptr, ptrindex);
LEAVE();
@@ -1407,8 +1387,22 @@ wlan_wmm_init(pmlan_adapter pmadapter)
= priv->aggr_prio_tbl[7].ampdu_user = BA_STREAM_NOT_ALLOWED;
priv->add_ba_param.timeout = MLAN_DEFAULT_BLOCK_ACK_TIMEOUT;
- priv->add_ba_param.tx_win_size = MLAN_AMPDU_DEF_TXWINSIZE;
- priv->add_ba_param.rx_win_size = MLAN_AMPDU_DEF_RXWINSIZE;
+#ifdef STA_SUPPORT
+ if (priv->bss_type == MLAN_BSS_TYPE_STA) {
+ priv->add_ba_param.tx_win_size = MLAN_STA_AMPDU_DEF_TXWINSIZE;
+ priv->add_ba_param.rx_win_size = MLAN_STA_AMPDU_DEF_RXWINSIZE;
+ }
+#endif
+#ifdef UAP_SUPPORT
+ if (priv->bss_type == MLAN_BSS_TYPE_UAP
+#ifdef WIFI_DIRECT_SUPPORT
+ || priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT
+#endif
+ ) {
+ priv->add_ba_param.tx_win_size = MLAN_UAP_AMPDU_DEF_TXWINSIZE;
+ priv->add_ba_param.rx_win_size = MLAN_UAP_AMPDU_DEF_RXWINSIZE;
+ }
+#endif
priv->add_ba_param.tx_amsdu = MTRUE;
priv->add_ba_param.rx_amsdu = MTRUE;
memset(priv->adapter, priv->rx_seq, 0xff, sizeof(priv->rx_seq));
@@ -1885,8 +1879,7 @@ wlan_wmm_process_association_req(pmlan_private priv,
if ((priv->wmm_required
|| (pHTCap && (pHTCap->ieee_hdr.element_id == HT_CAPABILITY)
- && (priv->adapter->config_bands & BAND_GN
- || priv->adapter->config_bands & BAND_AN))
+ && (priv->config_bands & BAND_GN || priv->config_bands & BAND_AN))
)
&& pWmmIE->vend_hdr.element_id == WMM_IE) {
pwmm_tlv = (MrvlIEtypes_WmmParamSet_t *) * ppAssocBuf;
@@ -2015,14 +2008,12 @@ wlan_wmm_select_queue(mlan_private * pmpriv, t_u8 tid)
* @param priv Pointer to the mlan_private driver data struct
* @param ra_list_head ra list header
* @param tid tid
- * @param tx_pause tx_pause flag
*
* @return N/A
*/
static INLINE t_u8
wlan_del_tx_pkts_in_ralist(pmlan_private priv,
- mlan_list_head * ra_list_head,
- int tid, t_u8 tx_pause)
+ mlan_list_head * ra_list_head, int tid)
{
raListTbl *ra_list = MNULL;
pmlan_adapter pmadapter = priv->adapter;
@@ -2034,15 +2025,14 @@ wlan_del_tx_pkts_in_ralist(pmlan_private priv,
MNULL, MNULL);
while (ra_list && ra_list != (raListTbl *) ra_list_head) {
if (ra_list->total_pkts && (ra_list->tx_pause ||
- (!tx_pause &&
- ra_list->total_pkts > RX_LOW_THRESHOLD))) {
+ (ra_list->total_pkts > RX_LOW_THRESHOLD))) {
if ((pmbuf =
(pmlan_buffer) util_dequeue_list(pmadapter->pmoal_handle,
&ra_list->buf_head, MNULL,
MNULL))) {
PRINTM(MDATA,
"Drop pkts: tid=%d tx_pause=%d pkts=%d brd_pkts=%d %02x:%02x:%02x:%02x:%02x:%02x\n",
- tid, tx_pause, ra_list->total_pkts,
+ tid, ra_list->tx_pause, ra_list->total_pkts,
pmadapter->pending_bridge_pkts, ra_list->ra[0],
ra_list->ra[1], ra_list->ra[2], ra_list->ra[3],
ra_list->ra[4], ra_list->ra[5]);
@@ -2077,17 +2067,14 @@ wlan_drop_tx_pkts(pmlan_private priv)
{
int j;
static int i = 0;
- t_u8 tx_pause = 0;
pmlan_adapter pmadapter = priv->adapter;
pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
priv->wmm.ra_list_spinlock);
- if (wlan_get_tx_pause_station_entry(priv))
- tx_pause = 1;
for (j = 0; j < MAX_NUM_TID; j++, i++) {
if (i == MAX_NUM_TID)
i = 0;
if (wlan_del_tx_pkts_in_ralist
- (priv, &priv->wmm.tid_tbl_ptr[i].ra_list, i, tx_pause)) {
+ (priv, &priv->wmm.tid_tbl_ptr[i].ra_list, i)) {
i++;
break;
}
diff --git a/drivers/net/wireless/sd8797/mlinux/mlan.h b/drivers/net/wireless/sd8797/mlinux/mlan.h
new file mode 100644
index 000000000000..a341e1547099
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/mlan.h
@@ -0,0 +1,35 @@
+/** @file mlan.h
+ *
+ * @brief This file declares all APIs that will be called from MOAL module.
+ * It also defines the data structures used for APIs between MLAN and MOAL.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+/******************************************************
+Change log:
+ 10/13/2008: initial version
+ 11/07/2008: split mlan.h into mlan_decl.h & mlan_ioctl.h
+******************************************************/
+
+#ifndef _MLAN_H_
+#define _MLAN_H_
+
+#include "mlan_decl.h"
+#include "mlan_ioctl.h"
+#include "mlan_ieee.h"
+
+#endif /* !_MLAN_H_ */
diff --git a/drivers/net/wireless/sd8797/mlinux/mlan_decl.h b/drivers/net/wireless/sd8797/mlinux/mlan_decl.h
new file mode 100644
index 000000000000..41cf2bf5f2f1
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/mlan_decl.h
@@ -0,0 +1,893 @@
+/** @file mlan_decl.h
+ *
+ * @brief This file declares the generic data structures and APIs.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+/******************************************************
+Change log:
+ 11/07/2008: initial version
+******************************************************/
+
+#ifndef _MLAN_DECL_H_
+#define _MLAN_DECL_H_
+
+/** MLAN release version */
+#define MLAN_RELEASE_VERSION "311"
+
+/** Re-define generic data types for MLAN/MOAL */
+/** Signed char (1-byte) */
+typedef char t_s8;
+/** Unsigned char (1-byte) */
+typedef unsigned char t_u8;
+/** Signed short (2-bytes) */
+typedef short t_s16;
+/** Unsigned short (2-bytes) */
+typedef unsigned short t_u16;
+/** Signed long (4-bytes) */
+typedef int t_s32;
+/** Unsigned long (4-bytes) */
+typedef unsigned int t_u32;
+/** Signed long long 8-bytes) */
+typedef long long t_s64;
+/** Unsigned long long 8-bytes) */
+typedef unsigned long long t_u64;
+/** Void pointer (4-bytes) */
+typedef void t_void;
+/** Size type */
+typedef t_u32 t_size;
+/** Boolean type */
+typedef t_u8 t_bool;
+
+#ifdef MLAN_64BIT
+/** Pointer type (64-bit) */
+typedef t_u64 t_ptr;
+/** Signed value (64-bit) */
+typedef t_s64 t_sval;
+#else
+/** Pointer type (32-bit) */
+typedef t_u32 t_ptr;
+/** Signed value (32-bit) */
+typedef t_s32 t_sval;
+#endif
+
+/** Constants below */
+
+#ifdef __GNUC__
+/** Structure packing begins */
+#define MLAN_PACK_START
+/** Structure packeing end */
+#define MLAN_PACK_END __attribute__ ((packed))
+#else /* !__GNUC__ */
+#ifdef PRAGMA_PACK
+/** Structure packing begins */
+#define MLAN_PACK_START
+/** Structure packeing end */
+#define MLAN_PACK_END
+#else /* !PRAGMA_PACK */
+/** Structure packing begins */
+#define MLAN_PACK_START __packed
+/** Structure packing end */
+#define MLAN_PACK_END
+#endif /* PRAGMA_PACK */
+#endif /* __GNUC__ */
+
+#ifndef INLINE
+#ifdef __GNUC__
+/** inline directive */
+#define INLINE inline
+#else
+/** inline directive */
+#define INLINE __inline
+#endif
+#endif
+
+/** MLAN TRUE */
+#define MTRUE (1)
+/** MLAN FALSE */
+#define MFALSE (0)
+
+/** Macros for Data Alignment : size */
+#define ALIGN_SZ(p, a) \
+ (((p) + ((a) - 1)) & ~((a) - 1))
+
+/** Macros for Data Alignment : address */
+#define ALIGN_ADDR(p, a) \
+ ((((t_ptr)(p)) + (((t_ptr)(a)) - 1)) & ~(((t_ptr)(a)) - 1))
+
+/** Return the byte offset of a field in the given structure */
+#define MLAN_FIELD_OFFSET(type, field) ((t_u32)(t_ptr)&(((type *)0)->field))
+/** Return aligned offset */
+#define OFFSET_ALIGN_ADDR(p, a) (t_u32)(ALIGN_ADDR(p, a) - (t_ptr)p)
+
+/** Maximum BSS numbers */
+#define MLAN_MAX_BSS_NUM (16)
+
+/** NET IP alignment */
+#define MLAN_NET_IP_ALIGN 0
+
+/** DMA alignment */
+#define DMA_ALIGNMENT 64
+/** max size of TxPD */
+#define MAX_TXPD_SIZE 32
+
+/** Minimum data header length */
+#define MLAN_MIN_DATA_HEADER_LEN (DMA_ALIGNMENT+MAX_TXPD_SIZE)
+
+/** rx data header length */
+#define MLAN_RX_HEADER_LEN MLAN_MIN_DATA_HEADER_LEN
+
+/** This is current limit on Maximum Tx AMPDU allowed */
+#define MLAN_MAX_TX_BASTREAM_SUPPORTED 2
+/** This is current limit on Maximum Rx AMPDU allowed */
+#define MLAN_MAX_RX_BASTREAM_SUPPORTED 16
+
+#ifdef STA_SUPPORT
+/** Default Win size attached during ADDBA request */
+#define MLAN_STA_AMPDU_DEF_TXWINSIZE 16
+/** Default Win size attached during ADDBA response */
+#define MLAN_STA_AMPDU_DEF_RXWINSIZE 32
+#endif /* STA_SUPPORT */
+#ifdef UAP_SUPPORT
+/** Default Win size attached during ADDBA request */
+#define MLAN_UAP_AMPDU_DEF_TXWINSIZE 32
+/** Default Win size attached during ADDBA response */
+#define MLAN_UAP_AMPDU_DEF_RXWINSIZE 16
+#endif /* UAP_SUPPORT */
+/** Block ack timeout value */
+#define MLAN_DEFAULT_BLOCK_ACK_TIMEOUT 0xffff
+/** Maximum Tx Win size configured for ADDBA request [10 bits] */
+#define MLAN_AMPDU_MAX_TXWINSIZE 0x3ff
+/** Maximum Rx Win size configured for ADDBA request [10 bits] */
+#define MLAN_AMPDU_MAX_RXWINSIZE 0x3ff
+
+/** Rate index for HR/DSSS 0 */
+#define MLAN_RATE_INDEX_HRDSSS0 0
+/** Rate index for HR/DSSS 3 */
+#define MLAN_RATE_INDEX_HRDSSS3 3
+/** Rate index for OFDM 0 */
+#define MLAN_RATE_INDEX_OFDM0 4
+/** Rate index for OFDM 7 */
+#define MLAN_RATE_INDEX_OFDM7 11
+/** Rate index for MCS 0 */
+#define MLAN_RATE_INDEX_MCS0 12
+/** Rate index for MCS 7 */
+#define MLAN_RATE_INDEX_MCS7 19
+/** Rate index for MCS 9 */
+#define MLAN_RATE_INDEX_MCS9 21
+/** Rate index for MCS15 */
+#define MLAN_RATE_INDEX_MCS15 27
+/** Rate index for MCS 32 */
+#define MLAN_RATE_INDEX_MCS32 44
+/** Rate index for MCS 127 */
+#define MLAN_RATE_INDEX_MCS127 139
+
+/** Rate bitmap for OFDM 0 */
+#define MLAN_RATE_BITMAP_OFDM0 16
+/** Rate bitmap for OFDM 7 */
+#define MLAN_RATE_BITMAP_OFDM7 23
+/** Rate bitmap for MCS 0 */
+#define MLAN_RATE_BITMAP_MCS0 32
+/** Rate bitmap for MCS 127 */
+#define MLAN_RATE_BITMAP_MCS127 159
+
+/** Size of rx data buffer */
+#define MLAN_RX_DATA_BUF_SIZE (4 * 1024)
+/** Size of rx command buffer */
+#define MLAN_RX_CMD_BUF_SIZE (2 * 1024)
+
+/** MLAN MAC Address Length */
+#define MLAN_MAC_ADDR_LENGTH (6)
+/** MLAN 802.11 MAC Address */
+typedef t_u8 mlan_802_11_mac_addr[MLAN_MAC_ADDR_LENGTH];
+
+/** MLAN Maximum SSID Length */
+#define MLAN_MAX_SSID_LENGTH (32)
+
+/** RTS/FRAG related defines */
+/** Minimum RTS value */
+#define MLAN_RTS_MIN_VALUE (0)
+/** Maximum RTS value */
+#define MLAN_RTS_MAX_VALUE (2347)
+/** Minimum FRAG value */
+#define MLAN_FRAG_MIN_VALUE (256)
+/** Maximum FRAG value */
+#define MLAN_FRAG_MAX_VALUE (2346)
+
+/** Minimum tx retry count */
+#define MLAN_TX_RETRY_MIN (0)
+/** Maximum tx retry count */
+#define MLAN_TX_RETRY_MAX (14)
+
+/** define SDIO block size for data Tx/Rx */
+/* We support up to 480-byte block size due to FW buffer limitation. */
+#define MLAN_SDIO_BLOCK_SIZE 256
+
+/** define SDIO block size for firmware download */
+#define MLAN_SDIO_BLOCK_SIZE_FW_DNLD MLAN_SDIO_BLOCK_SIZE
+
+/** define allocated buffer size */
+#define ALLOC_BUF_SIZE (4 * 1024)
+
+/** SDIO IO Port mask */
+#define MLAN_SDIO_IO_PORT_MASK 0xfffff
+/** SDIO Block/Byte mode mask */
+#define MLAN_SDIO_BYTE_MODE_MASK 0x80000000
+
+/** Max retry number of IO write */
+#define MAX_WRITE_IOMEM_RETRY 2
+
+/** IN parameter */
+#define IN
+/** OUT parameter */
+#define OUT
+
+/** BIT value */
+#define MBIT(x) (((t_u32)1) << (x))
+
+/** Buffer flag for requeued packet */
+#define MLAN_BUF_FLAG_REQUEUED_PKT MBIT(0)
+/** Buffer flag for transmit buf from moal */
+#define MLAN_BUF_FLAG_MOAL_TX_BUF MBIT(1)
+/** Buffer flag for malloc mlan_buffer */
+#define MLAN_BUF_FLAG_MALLOC_BUF MBIT(2)
+
+/** Buffer flag for bridge packet */
+#define MLAN_BUF_FLAG_BRIDGE_BUF MBIT(3)
+
+#ifdef DEBUG_LEVEL1
+/** Debug level bit definition */
+#define MMSG MBIT(0)
+#define MFATAL MBIT(1)
+#define MERROR MBIT(2)
+#define MDATA MBIT(3)
+#define MCMND MBIT(4)
+#define MEVENT MBIT(5)
+#define MINTR MBIT(6)
+#define MIOCTL MBIT(7)
+
+#define MDAT_D MBIT(16)
+#define MCMD_D MBIT(17)
+#define MEVT_D MBIT(18)
+#define MFW_D MBIT(19)
+#define MIF_D MBIT(20)
+
+#define MENTRY MBIT(28)
+#define MWARN MBIT(29)
+#define MINFO MBIT(30)
+#define MHEX_DUMP MBIT(31)
+#endif /* DEBUG_LEVEL1 */
+
+/** Memory allocation type: DMA */
+#define MLAN_MEM_DMA MBIT(0)
+
+/** Default memory allocation flag */
+#define MLAN_MEM_DEF 0
+
+/** mlan_status */
+typedef enum _mlan_status
+{
+ MLAN_STATUS_FAILURE = 0xffffffff,
+ MLAN_STATUS_SUCCESS = 0,
+ MLAN_STATUS_PENDING,
+ MLAN_STATUS_RESOURCE,
+} mlan_status;
+
+/** mlan_error_code */
+typedef enum _mlan_error_code
+{
+ /** No error */
+ MLAN_ERROR_NO_ERROR = 0,
+ /** Firmware/device errors below (MSB=0) */
+ MLAN_ERROR_FW_NOT_READY = 0x00000001,
+ MLAN_ERROR_FW_BUSY,
+ MLAN_ERROR_FW_CMDRESP,
+ MLAN_ERROR_DATA_TX_FAIL,
+ MLAN_ERROR_DATA_RX_FAIL,
+ /** Driver errors below (MSB=1) */
+ MLAN_ERROR_PKT_SIZE_INVALID = 0x80000001,
+ MLAN_ERROR_PKT_TIMEOUT,
+ MLAN_ERROR_PKT_INVALID,
+ MLAN_ERROR_CMD_INVALID,
+ MLAN_ERROR_CMD_TIMEOUT,
+ MLAN_ERROR_CMD_DNLD_FAIL,
+ MLAN_ERROR_CMD_CANCEL,
+ MLAN_ERROR_CMD_RESP_FAIL,
+ MLAN_ERROR_CMD_ASSOC_FAIL,
+ MLAN_ERROR_CMD_SCAN_FAIL,
+ MLAN_ERROR_IOCTL_INVALID,
+ MLAN_ERROR_IOCTL_FAIL,
+ MLAN_ERROR_EVENT_UNKNOWN,
+ MLAN_ERROR_INVALID_PARAMETER,
+ MLAN_ERROR_NO_MEM,
+ /** More to add */
+} mlan_error_code;
+
+/** mlan_buf_type */
+typedef enum _mlan_buf_type
+{
+ MLAN_BUF_TYPE_CMD = 1,
+ MLAN_BUF_TYPE_DATA,
+ MLAN_BUF_TYPE_EVENT,
+ MLAN_BUF_TYPE_RAW_DATA,
+} mlan_buf_type;
+
+/** MLAN BSS type */
+typedef enum _mlan_bss_type
+{
+ MLAN_BSS_TYPE_STA = 0,
+ MLAN_BSS_TYPE_UAP = 1,
+#ifdef WIFI_DIRECT_SUPPORT
+ MLAN_BSS_TYPE_WIFIDIRECT = 2,
+#endif
+ MLAN_BSS_TYPE_ANY = 0xff,
+} mlan_bss_type;
+
+/** MLAN BSS role */
+typedef enum _mlan_bss_role
+{
+ MLAN_BSS_ROLE_STA = 0,
+ MLAN_BSS_ROLE_UAP = 1,
+ MLAN_BSS_ROLE_ANY = 0xff,
+} mlan_bss_role;
+
+/** BSS role bit mask */
+#define BSS_ROLE_BIT_MASK MBIT(0)
+
+/** Get BSS role */
+#define GET_BSS_ROLE(priv) ((priv)->bss_role & BSS_ROLE_BIT_MASK)
+
+/** mlan_data_frame_type */
+typedef enum _mlan_data_frame_type
+{
+ MLAN_DATA_FRAME_TYPE_ETH_II = 0,
+ MLAN_DATA_FRAME_TYPE_802_11,
+} mlan_data_frame_type;
+
+/** mlan_event_id */
+typedef enum _mlan_event_id
+{
+ /* Event generated by firmware (MSB=0) */
+ MLAN_EVENT_ID_FW_UNKNOWN = 0x00000001,
+ MLAN_EVENT_ID_FW_ADHOC_LINK_SENSED,
+ MLAN_EVENT_ID_FW_ADHOC_LINK_LOST,
+ MLAN_EVENT_ID_FW_DISCONNECTED,
+ MLAN_EVENT_ID_FW_MIC_ERR_UNI,
+ MLAN_EVENT_ID_FW_MIC_ERR_MUL,
+ MLAN_EVENT_ID_FW_BCN_RSSI_LOW,
+ MLAN_EVENT_ID_FW_BCN_RSSI_HIGH,
+ MLAN_EVENT_ID_FW_BCN_SNR_LOW,
+ MLAN_EVENT_ID_FW_BCN_SNR_HIGH,
+ MLAN_EVENT_ID_FW_MAX_FAIL,
+ MLAN_EVENT_ID_FW_DATA_RSSI_LOW,
+ MLAN_EVENT_ID_FW_DATA_RSSI_HIGH,
+ MLAN_EVENT_ID_FW_DATA_SNR_LOW,
+ MLAN_EVENT_ID_FW_DATA_SNR_HIGH,
+ MLAN_EVENT_ID_FW_LINK_QUALITY,
+ MLAN_EVENT_ID_FW_PORT_RELEASE,
+ MLAN_EVENT_ID_FW_PRE_BCN_LOST,
+ MLAN_EVENT_ID_FW_WMM_CONFIG_CHANGE,
+ MLAN_EVENT_ID_FW_HS_WAKEUP,
+ MLAN_EVENT_ID_FW_BG_SCAN,
+ MLAN_EVENT_ID_FW_WEP_ICV_ERR,
+ MLAN_EVENT_ID_FW_STOP_TX,
+ MLAN_EVENT_ID_FW_START_TX,
+ MLAN_EVENT_ID_FW_CHANNEL_SWITCH_ANN,
+ MLAN_EVENT_ID_FW_RADAR_DETECTED,
+ MLAN_EVENT_ID_FW_CHANNEL_REPORT_RDY,
+ MLAN_EVENT_ID_FW_BW_CHANGED,
+#ifdef WIFI_DIRECT_SUPPORT
+ MLAN_EVENT_ID_FW_REMAIN_ON_CHAN_EXPIRED,
+#endif
+#ifdef UAP_SUPPORT
+ MLAN_EVENT_ID_UAP_FW_BSS_START,
+ MLAN_EVENT_ID_UAP_FW_BSS_ACTIVE,
+ MLAN_EVENT_ID_UAP_FW_BSS_IDLE,
+ MLAN_EVENT_ID_UAP_FW_STA_CONNECT,
+ MLAN_EVENT_ID_UAP_FW_STA_DISCONNECT,
+#endif
+
+ /* Event generated by MLAN driver (MSB=1) */
+ MLAN_EVENT_ID_DRV_CONNECTED = 0x80000001,
+ MLAN_EVENT_ID_DRV_DEFER_HANDLING,
+ MLAN_EVENT_ID_DRV_HS_ACTIVATED,
+ MLAN_EVENT_ID_DRV_HS_DEACTIVATED,
+ MLAN_EVENT_ID_DRV_MGMT_FRAME,
+ MLAN_EVENT_ID_DRV_OBSS_SCAN_PARAM,
+ MLAN_EVENT_ID_DRV_PASSTHRU,
+ MLAN_EVENT_ID_DRV_SCAN_REPORT,
+ MLAN_EVENT_ID_DRV_MEAS_REPORT,
+ MLAN_EVENT_ID_DRV_REPORT_STRING,
+ MLAN_EVENT_ID_DRV_DBG_DUMP,
+} mlan_event_id;
+
+/** Data Structures */
+/** mlan_image data structure */
+typedef struct _mlan_fw_image
+{
+ /** Helper image buffer pointer */
+ t_u8 *phelper_buf;
+ /** Helper image length */
+ t_u32 helper_len;
+ /** Firmware image buffer pointer */
+ t_u8 *pfw_buf;
+ /** Firmware image length */
+ t_u32 fw_len;
+} mlan_fw_image, *pmlan_fw_image;
+
+/** Custom data structure */
+typedef struct _mlan_init_param
+{
+ /** Cal data buffer pointer */
+ t_u8 *pcal_data_buf;
+ /** Cal data length */
+ t_u32 cal_data_len;
+ /** Other custom data */
+} mlan_init_param, *pmlan_init_param;
+
+/** mlan_event data structure */
+typedef struct _mlan_event
+{
+ /** BSS index number for multiple BSS support */
+ t_u32 bss_index;
+ /** Event ID */
+ mlan_event_id event_id;
+ /** Event length */
+ t_u32 event_len;
+ /** Event buffer */
+ t_u8 event_buf[1];
+} mlan_event, *pmlan_event;
+
+/** mlan_event_scan_result data structure */
+typedef MLAN_PACK_START struct _mlan_event_scan_result
+{
+ /** Event ID */
+ t_u16 event_id;
+ /** BSS index number for multiple BSS support */
+ t_u8 bss_index;
+ /** BSS type */
+ t_u8 bss_type;
+ /** More event available or not */
+ t_u8 more_event;
+ /** Reserved */
+ t_u8 reserved[3];
+ /** Size of the response buffer */
+ t_u16 buf_size;
+ /** Number of BSS in scan response */
+ t_u8 num_of_set;
+} MLAN_PACK_END mlan_event_scan_result, *pmlan_event_scan_result;
+
+/** mlan_ioctl_req data structure */
+typedef struct _mlan_ioctl_req
+{
+ /** Status code from firmware/driver */
+ t_u32 status_code;
+ /** BSS index number for multiple BSS support */
+ t_u32 bss_index;
+ /** Request id */
+ t_u32 req_id;
+ /** Action: set or get */
+ t_u32 action;
+ /** Pointer to buffer */
+ t_u8 *pbuf;
+ /** Length of buffer */
+ t_u32 buf_len;
+ /** Length of the data read/written in buffer */
+ t_u32 data_read_written;
+ /** Length of buffer needed */
+ t_u32 buf_len_needed;
+ /** Reserved for MOAL module */
+ t_ptr reserved_1;
+} mlan_ioctl_req, *pmlan_ioctl_req;
+
+/** mlan_buffer data structure */
+typedef struct _mlan_buffer
+{
+ /** Pointer to previous mlan_buffer */
+ struct _mlan_buffer *pprev;
+ /** Pointer to next mlan_buffer */
+ struct _mlan_buffer *pnext;
+ /** Status code from firmware/driver */
+ t_u32 status_code;
+ /** Flags for this buffer */
+ t_u32 flags;
+ /** BSS index number for multiple BSS support */
+ t_u32 bss_index;
+ /** Buffer descriptor, e.g. skb in Linux */
+ t_void *pdesc;
+ /** Pointer to buffer */
+ t_u8 *pbuf;
+ /** Offset to data */
+ t_u32 data_offset;
+ /** Data length */
+ t_u32 data_len;
+ /** Buffer type: data, cmd, event etc. */
+ mlan_buf_type buf_type;
+
+ /** Fields below are valid for data packet only */
+ /** QoS priority */
+ t_u32 priority;
+ /** Time stamp when packet is received (seconds) */
+ t_u32 in_ts_sec;
+ /** Time stamp when packet is received (micro seconds) */
+ t_u32 in_ts_usec;
+ /** Time stamp when packet is processed (seconds) */
+ t_u32 out_ts_sec;
+ /** Time stamp when packet is processed (micro seconds) */
+ t_u32 out_ts_usec;
+
+ /** Fields below are valid for MLAN module only */
+ /** Pointer to parent mlan_buffer */
+ struct _mlan_buffer *pparent;
+ /** Use count for this buffer */
+ t_u32 use_count;
+} mlan_buffer, *pmlan_buffer;
+
+/** mlan_bss_attr data structure */
+typedef struct _mlan_bss_attr
+{
+ /** BSS type */
+ t_u32 bss_type;
+ /** Data frame type: Ethernet II, 802.11, etc. */
+ t_u32 frame_type;
+ /** The BSS is active (non-0) or not (0). */
+ t_u32 active;
+ /** BSS Priority */
+ t_u32 bss_priority;
+ /** BSS number */
+ t_u32 bss_num;
+} mlan_bss_attr, *pmlan_bss_attr;
+
+#ifdef PRAGMA_PACK
+#pragma pack(push, 1)
+#endif
+
+/** Type enumeration for the command result */
+typedef MLAN_PACK_START enum _mlan_cmd_result_e
+{
+ MLAN_CMD_RESULT_SUCCESS = 0,
+ MLAN_CMD_RESULT_FAILURE = 1,
+ MLAN_CMD_RESULT_TIMEOUT = 2,
+ MLAN_CMD_RESULT_INVALID_DATA = 3
+} MLAN_PACK_END mlan_cmd_result_e;
+
+/** Type enumeration of WMM AC_QUEUES */
+typedef MLAN_PACK_START enum _mlan_wmm_ac_e
+{
+ WMM_AC_BK,
+ WMM_AC_BE,
+ WMM_AC_VI,
+ WMM_AC_VO
+} MLAN_PACK_END mlan_wmm_ac_e;
+
+/** Type enumeration for the action field in the Queue Config command */
+typedef MLAN_PACK_START enum _mlan_wmm_queue_config_action_e
+{
+ MLAN_WMM_QUEUE_CONFIG_ACTION_GET = 0,
+ MLAN_WMM_QUEUE_CONFIG_ACTION_SET = 1,
+ MLAN_WMM_QUEUE_CONFIG_ACTION_DEFAULT = 2,
+ MLAN_WMM_QUEUE_CONFIG_ACTION_MAX
+} MLAN_PACK_END mlan_wmm_queue_config_action_e;
+
+/** Type enumeration for the action field in the queue stats command */
+typedef MLAN_PACK_START enum _mlan_wmm_queue_stats_action_e
+{
+ MLAN_WMM_STATS_ACTION_START = 0,
+ MLAN_WMM_STATS_ACTION_STOP = 1,
+ MLAN_WMM_STATS_ACTION_GET_CLR = 2,
+ MLAN_WMM_STATS_ACTION_SET_CFG = 3, /* Not currently used */
+ MLAN_WMM_STATS_ACTION_GET_CFG = 4, /* Not currently used */
+ MLAN_WMM_STATS_ACTION_MAX
+} MLAN_PACK_END mlan_wmm_queue_stats_action_e;
+
+/**
+ * @brief IOCTL structure for a Traffic stream status.
+ *
+ */
+typedef MLAN_PACK_START struct
+{
+ /** TSID: Range: 0->7 */
+ t_u8 tid;
+ /** TSID specified is valid */
+ t_u8 valid;
+ /** AC TSID is active on */
+ t_u8 access_category;
+ /** UP specified for the TSID */
+ t_u8 user_priority;
+ /** Power save mode for TSID: 0 (legacy), 1 (UAPSD) */
+ t_u8 psb;
+ /** Upstream(0), Downlink(1), Bidirectional(3) */
+ t_u8 flow_dir;
+ /** Medium time granted for the TSID */
+ t_u16 medium_time;
+} MLAN_PACK_END wlan_ioctl_wmm_ts_status_t,
+/** Type definition of mlan_ds_wmm_ts_status for MLAN_OID_WMM_CFG_TS_STATUS */
+ mlan_ds_wmm_ts_status, *pmlan_ds_wmm_ts_status;
+
+/** Max Ie length */
+#define MAX_IE_SIZE 256
+
+/** custom IE */
+typedef MLAN_PACK_START struct _custom_ie
+{
+ /** IE Index */
+ t_u16 ie_index;
+ /** Mgmt Subtype Mask */
+ t_u16 mgmt_subtype_mask;
+ /** IE Length */
+ t_u16 ie_length;
+ /** IE buffer */
+ t_u8 ie_buffer[MAX_IE_SIZE];
+} MLAN_PACK_END custom_ie;
+
+/** Max IE index to FW */
+#define MAX_MGMT_IE_INDEX_TO_FW 4
+/** Max IE index per BSS */
+#define MAX_MGMT_IE_INDEX 16
+
+/** custom IE info */
+typedef MLAN_PACK_START struct _custom_ie_info
+{
+ /** size of buffer */
+ t_u16 buf_size;
+ /** no of buffers of buf_size */
+ t_u16 buf_count;
+} MLAN_PACK_END custom_ie_info;
+
+/** TLV buffer : Max Mgmt IE */
+typedef MLAN_PACK_START struct _tlvbuf_max_mgmt_ie
+{
+ /** Type */
+ t_u16 type;
+ /** Length */
+ t_u16 len;
+ /** No of tuples */
+ t_u16 count;
+ /** custom IE info tuples */
+ custom_ie_info info[MAX_MGMT_IE_INDEX];
+} MLAN_PACK_END tlvbuf_max_mgmt_ie;
+
+/** TLV buffer : custom IE */
+typedef MLAN_PACK_START struct _tlvbuf_custom_ie
+{
+ /** Type */
+ t_u16 type;
+ /** Length */
+ t_u16 len;
+ /** IE data */
+ custom_ie ie_data_list[MAX_MGMT_IE_INDEX_TO_FW];
+ /** Max mgmt IE TLV */
+ tlvbuf_max_mgmt_ie max_mgmt_ie;
+} MLAN_PACK_END mlan_ds_misc_custom_ie;
+
+#ifdef PRAGMA_PACK
+#pragma pack(pop)
+#endif
+
+/** mlan_callbacks data structure */
+typedef struct _mlan_callbacks
+{
+ /** moal_get_fw_data */
+ mlan_status(*moal_get_fw_data) (IN t_void * pmoal_handle,
+ IN t_u32 offset,
+ IN t_u32 len, OUT t_u8 * pbuf);
+ /** moal_init_fw_complete */
+ mlan_status(*moal_init_fw_complete) (IN t_void * pmoal_handle,
+ IN mlan_status status);
+ /** moal_shutdown_fw_complete */
+ mlan_status(*moal_shutdown_fw_complete) (IN t_void * pmoal_handle,
+ IN mlan_status status);
+ /** moal_send_packet_complete */
+ mlan_status(*moal_send_packet_complete) (IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf,
+ IN mlan_status status);
+ /** moal_recv_complete */
+ mlan_status(*moal_recv_complete) (IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf,
+ IN t_u32 port, IN mlan_status status);
+ /** moal_recv_packet */
+ mlan_status(*moal_recv_packet) (IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf);
+ /** moal_recv_event */
+ mlan_status(*moal_recv_event) (IN t_void * pmoal_handle,
+ IN pmlan_event pmevent);
+ /** moal_ioctl_complete */
+ mlan_status(*moal_ioctl_complete) (IN t_void * pmoal_handle,
+ IN pmlan_ioctl_req pioctl_req,
+ IN mlan_status status);
+ /** moal_alloc_mlan_buffer */
+ mlan_status(*moal_alloc_mlan_buffer) (IN t_void * pmoal_handle,
+ IN t_u32 size,
+ OUT pmlan_buffer * pmbuf);
+ /** moal_free_mlan_buffer */
+ mlan_status(*moal_free_mlan_buffer) (IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf);
+ /** moal_write_reg */
+ mlan_status(*moal_write_reg) (IN t_void * pmoal_handle,
+ IN t_u32 reg, IN t_u32 data);
+ /** moal_read_reg */
+ mlan_status(*moal_read_reg) (IN t_void * pmoal_handle,
+ IN t_u32 reg, OUT t_u32 * data);
+ /** moal_write_data_sync */
+ mlan_status(*moal_write_data_sync) (IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf,
+ IN t_u32 port, IN t_u32 timeout);
+ /** moal_read_data_sync */
+ mlan_status(*moal_read_data_sync) (IN t_void * pmoal_handle,
+ IN OUT pmlan_buffer pmbuf,
+ IN t_u32 port, IN t_u32 timeout);
+ /** moal_malloc */
+ mlan_status(*moal_malloc) (IN t_void * pmoal_handle,
+ IN t_u32 size, IN t_u32 flag, OUT t_u8 ** ppbuf);
+ /** moal_mfree */
+ mlan_status(*moal_mfree) (IN t_void * pmoal_handle, IN t_u8 * pbuf);
+ /** moal_memset */
+ t_void *(*moal_memset) (IN t_void * pmoal_handle,
+ IN t_void * pmem, IN t_u8 byte, IN t_u32 num);
+ /** moal_memcpy */
+ t_void *(*moal_memcpy) (IN t_void * pmoal_handle,
+ IN t_void * pdest,
+ IN const t_void * psrc, IN t_u32 num);
+ /** moal_memmove */
+ t_void *(*moal_memmove) (IN t_void * pmoal_handle,
+ IN t_void * pdest,
+ IN const t_void * psrc, IN t_u32 num);
+ /** moal_memcmp */
+ t_s32(*moal_memcmp) (IN t_void * pmoal_handle,
+ IN const t_void * pmem1,
+ IN const t_void * pmem2, IN t_u32 num);
+ /** moal_udelay */
+ t_void(*moal_udelay) (IN t_void * pmoal_handle, IN t_u32 udelay);
+ /** moal_get_system_time */
+ mlan_status(*moal_get_system_time) (IN t_void * pmoal_handle,
+ OUT t_u32 * psec, OUT t_u32 * pusec);
+ /** moal_init_timer*/
+ mlan_status(*moal_init_timer) (IN t_void * pmoal_handle,
+ OUT t_void ** pptimer,
+ IN t_void(*callback) (t_void * pcontext),
+ IN t_void * pcontext);
+ /** moal_free_timer */
+ mlan_status(*moal_free_timer) (IN t_void * pmoal_handle,
+ IN t_void * ptimer);
+ /** moal_start_timer*/
+ mlan_status(*moal_start_timer) (IN t_void * pmoal_handle,
+ IN t_void * ptimer,
+ IN t_u8 periodic, IN t_u32 msec);
+ /** moal_stop_timer*/
+ mlan_status(*moal_stop_timer) (IN t_void * pmoal_handle,
+ IN t_void * ptimer);
+ /** moal_init_lock */
+ mlan_status(*moal_init_lock) (IN t_void * pmoal_handle,
+ OUT t_void ** pplock);
+ /** moal_free_lock */
+ mlan_status(*moal_free_lock) (IN t_void * pmoal_handle,
+ IN t_void * plock);
+ /** moal_spin_lock */
+ mlan_status(*moal_spin_lock) (IN t_void * pmoal_handle,
+ IN t_void * plock);
+ /** moal_spin_unlock */
+ mlan_status(*moal_spin_unlock) (IN t_void * pmoal_handle,
+ IN t_void * plock);
+ /** moal_print */
+ t_void(*moal_print) (IN t_void * pmoal_handle,
+ IN t_u32 level, IN t_s8 * pformat, IN ...);
+ /** moal_print_netintf */
+ t_void(*moal_print_netintf) (IN t_void * pmoal_handle,
+ IN t_u32 bss_index, IN t_u32 level);
+ /** moal_assert */
+ t_void(*moal_assert) (IN t_void * pmoal_handle, IN t_u32 cond);
+} mlan_callbacks, *pmlan_callbacks;
+
+/** Interrupt Mode SDIO */
+#define INT_MODE_SDIO 0
+/** Interrupt Mode GPIO */
+#define INT_MODE_GPIO 1
+
+/** Parameter unchanged, use MLAN default setting */
+#define MLAN_INIT_PARA_UNCHANGED 0
+/** Parameter enabled, override MLAN default setting */
+#define MLAN_INIT_PARA_ENABLED 1
+/** Parameter disabled, override MLAN default setting */
+#define MLAN_INIT_PARA_DISABLED 2
+
+/** mlan_device data structure */
+typedef struct _mlan_device
+{
+ /** MOAL Handle */
+ t_void *pmoal_handle;
+ /** BSS Attributes */
+ mlan_bss_attr bss_attr[MLAN_MAX_BSS_NUM];
+ /** Callbacks */
+ mlan_callbacks callbacks;
+#ifdef MFG_CMD_SUPPORT
+ /** MFG mode */
+ t_u32 mfg_mode;
+#endif
+ /** SDIO interrupt mode (0: INT_MODE_SDIO, 1: INT_MODE_GPIO) */
+ t_u32 int_mode;
+ /** GPIO interrupt pin number */
+ t_u32 gpio_pin;
+#ifdef DEBUG_LEVEL1
+ /** Driver debug bit masks */
+ t_u32 drvdbg;
+#endif
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+ /** SDIO MPA Tx */
+ t_u32 mpa_tx_cfg;
+#endif
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+ /** SDIO MPA Rx */
+ t_u32 mpa_rx_cfg;
+#endif
+ /** Auto deep sleep */
+ t_u32 auto_ds;
+ /** IEEE PS mode */
+ t_u32 ps_mode;
+ /** Max Tx buffer size */
+ t_u32 max_tx_buf;
+#if defined(STA_SUPPORT)
+ /** 802.11d configuration */
+ t_u32 cfg_11d;
+#endif
+} mlan_device, *pmlan_device;
+
+/** MLAN API function prototype */
+#define MLAN_API
+
+/** Registration */
+MLAN_API mlan_status mlan_register(IN pmlan_device pmdevice,
+ OUT t_void ** ppmlan_adapter);
+
+/** Un-registration */
+MLAN_API mlan_status mlan_unregister(IN t_void * pmlan_adapter);
+
+/** Firmware Downloading */
+MLAN_API mlan_status mlan_dnld_fw(IN t_void * pmlan_adapter,
+ IN pmlan_fw_image pmfw);
+
+/** Custom data pass API */
+MLAN_API mlan_status mlan_set_init_param(IN t_void * pmlan_adapter,
+ IN pmlan_init_param pparam);
+
+/** Firmware Initialization */
+MLAN_API mlan_status mlan_init_fw(IN t_void * pmlan_adapter);
+
+/** Firmware Shutdown */
+MLAN_API mlan_status mlan_shutdown_fw(IN t_void * pmlan_adapter);
+
+/** Main Process */
+MLAN_API mlan_status mlan_main_process(IN t_void * pmlan_adapter);
+
+/** Packet Transmission */
+MLAN_API mlan_status mlan_send_packet(IN t_void * pmlan_adapter,
+ IN pmlan_buffer pmbuf);
+
+/** Packet Reception complete callback */
+MLAN_API mlan_status mlan_recv_packet_complete(IN t_void * pmlan_adapter,
+ IN pmlan_buffer pmbuf,
+ IN mlan_status status);
+
+/** interrupt handler */
+MLAN_API t_void mlan_interrupt(IN t_void * pmlan_adapter);
+
+/** mlan ioctl */
+MLAN_API mlan_status mlan_ioctl(IN t_void * pmlan_adapter,
+ IN pmlan_ioctl_req pioctl_req);
+/** mlan select wmm queue */
+MLAN_API t_u8 mlan_select_wmm_queue(IN t_void * pmlan_adapter,
+ IN t_u8 bss_num, IN t_u8 tid);
+#endif /* !_MLAN_DECL_H_ */
diff --git a/drivers/net/wireless/sd8797/mlinux/mlan_ieee.h b/drivers/net/wireless/sd8797/mlinux/mlan_ieee.h
new file mode 100644
index 000000000000..2431e06f48fa
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/mlan_ieee.h
@@ -0,0 +1,1322 @@
+/** @file mlan_ieee.h
+ *
+ * @brief This file contains IEEE information element related
+ * definitions used in MLAN and MOAL module.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+/******************************************************
+Change log:
+ 11/03/2008: initial version
+******************************************************/
+
+#ifndef _MLAN_IEEE_H_
+#define _MLAN_IEEE_H_
+
+/** FIX IES size in beacon buffer */
+#define WLAN_802_11_FIXED_IE_SIZE 12
+/** WLAN supported rates */
+#define WLAN_SUPPORTED_RATES 14
+
+/** WLAN supported rates extension*/
+#define WLAN_SUPPORTED_RATES_EXT 32
+
+/** Enumeration definition*/
+/** WLAN_802_11_NETWORK_TYPE */
+typedef enum _WLAN_802_11_NETWORK_TYPE
+{
+ Wlan802_11FH,
+ Wlan802_11DS,
+ /* Defined as upper bound */
+ Wlan802_11NetworkTypeMax
+} WLAN_802_11_NETWORK_TYPE;
+
+/** Maximum size of IEEE Information Elements */
+#define IEEE_MAX_IE_SIZE 256
+
+#ifdef BIG_ENDIAN_SUPPORT
+/** Frame control: Type Mgmt frame */
+#define IEEE80211_FC_MGMT_FRAME_TYPE_MASK 0x3000
+/** Frame control: SubType Mgmt frame */
+#define IEEE80211_GET_FC_MGMT_FRAME_SUBTYPE(fc) (((fc) & 0xF000) >> 12)
+#else
+/** Frame control: Type Mgmt frame */
+#define IEEE80211_FC_MGMT_FRAME_TYPE_MASK 0x000C
+/** Frame control: SubType Mgmt frame */
+#define IEEE80211_GET_FC_MGMT_FRAME_SUBTYPE(fc) (((fc) & 0x00F0) >> 4)
+#endif
+
+#ifdef PRAGMA_PACK
+#pragma pack(push, 1)
+#endif
+
+/** IEEE Type definitions */
+typedef MLAN_PACK_START enum _IEEEtypes_ElementId_e
+{
+ SSID = 0,
+ SUPPORTED_RATES = 1,
+
+ FH_PARAM_SET = 2,
+ DS_PARAM_SET = 3,
+ CF_PARAM_SET = 4,
+
+ IBSS_PARAM_SET = 6,
+
+#ifdef STA_SUPPORT
+ COUNTRY_INFO = 7,
+#endif /* STA_SUPPORT */
+
+ POWER_CONSTRAINT = 32,
+ POWER_CAPABILITY = 33,
+ TPC_REQUEST = 34,
+ TPC_REPORT = 35,
+ SUPPORTED_CHANNELS = 36,
+ CHANNEL_SWITCH_ANN = 37,
+ QUIET = 40,
+ IBSS_DFS = 41,
+ HT_CAPABILITY = 45,
+ HT_OPERATION = 61,
+ BSSCO_2040 = 72,
+ OVERLAPBSSSCANPARAM = 74,
+ EXT_CAPABILITY = 127,
+
+ ERP_INFO = 42,
+
+ EXTENDED_SUPPORTED_RATES = 50,
+
+ VENDOR_SPECIFIC_221 = 221,
+ WMM_IE = VENDOR_SPECIFIC_221,
+
+ WPS_IE = VENDOR_SPECIFIC_221,
+
+ WPA_IE = VENDOR_SPECIFIC_221,
+ RSN_IE = 48,
+ VS_IE = VENDOR_SPECIFIC_221,
+ WAPI_IE = 68,
+} MLAN_PACK_END IEEEtypes_ElementId_e;
+
+/** IEEE IE header */
+typedef MLAN_PACK_START struct _IEEEtypes_Header_t
+{
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+} MLAN_PACK_END IEEEtypes_Header_t, *pIEEEtypes_Header_t;
+
+/** Vendor specific IE header */
+typedef MLAN_PACK_START struct _IEEEtypes_VendorHeader_t
+{
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+ /** OUI */
+ t_u8 oui[3];
+ /** OUI type */
+ t_u8 oui_type;
+ /** OUI subtype */
+ t_u8 oui_subtype;
+ /** Version */
+ t_u8 version;
+} MLAN_PACK_END IEEEtypes_VendorHeader_t, *pIEEEtypes_VendorHeader_t;
+
+/** Vendor specific IE */
+typedef MLAN_PACK_START struct _IEEEtypes_VendorSpecific_t
+{
+ /** Vendor specific IE header */
+ IEEEtypes_VendorHeader_t vend_hdr;
+ /** IE Max - size of previous fields */
+ t_u8 data[IEEE_MAX_IE_SIZE - sizeof(IEEEtypes_VendorHeader_t)];
+}
+MLAN_PACK_END IEEEtypes_VendorSpecific_t, *pIEEEtypes_VendorSpecific_t;
+
+/** IEEE IE */
+typedef MLAN_PACK_START struct _IEEEtypes_Generic_t
+{
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** IE Max - size of previous fields */
+ t_u8 data[IEEE_MAX_IE_SIZE - sizeof(IEEEtypes_Header_t)];
+}
+MLAN_PACK_END IEEEtypes_Generic_t, *pIEEEtypes_Generic_t;
+
+/** Capability information mask */
+#define CAPINFO_MASK (~(MBIT(15) | MBIT(14) | \
+ MBIT(12) | MBIT(11) | MBIT(9)))
+
+/** Capability Bit Map*/
+#ifdef BIG_ENDIAN_SUPPORT
+typedef MLAN_PACK_START struct _IEEEtypes_CapInfo_t
+{
+ t_u8 rsrvd1:2;
+ t_u8 dsss_ofdm:1;
+ t_u8 rsvrd2:2;
+ t_u8 short_slot_time:1;
+ t_u8 rsrvd3:1;
+ t_u8 spectrum_mgmt:1;
+ t_u8 chan_agility:1;
+ t_u8 pbcc:1;
+ t_u8 short_preamble:1;
+ t_u8 privacy:1;
+ t_u8 cf_poll_rqst:1;
+ t_u8 cf_pollable:1;
+ t_u8 ibss:1;
+ t_u8 ess:1;
+} MLAN_PACK_END IEEEtypes_CapInfo_t, *pIEEEtypes_CapInfo_t;
+#else
+typedef MLAN_PACK_START struct _IEEEtypes_CapInfo_t
+{
+ /** Capability Bit Map : ESS */
+ t_u8 ess:1;
+ /** Capability Bit Map : IBSS */
+ t_u8 ibss:1;
+ /** Capability Bit Map : CF pollable */
+ t_u8 cf_pollable:1;
+ /** Capability Bit Map : CF poll request */
+ t_u8 cf_poll_rqst:1;
+ /** Capability Bit Map : privacy */
+ t_u8 privacy:1;
+ /** Capability Bit Map : Short preamble */
+ t_u8 short_preamble:1;
+ /** Capability Bit Map : PBCC */
+ t_u8 pbcc:1;
+ /** Capability Bit Map : Channel agility */
+ t_u8 chan_agility:1;
+ /** Capability Bit Map : Spectrum management */
+ t_u8 spectrum_mgmt:1;
+ /** Capability Bit Map : Reserved */
+ t_u8 rsrvd3:1;
+ /** Capability Bit Map : Short slot time */
+ t_u8 short_slot_time:1;
+ /** Capability Bit Map : APSD */
+ t_u8 Apsd:1;
+ /** Capability Bit Map : Reserved */
+ t_u8 rsvrd2:1;
+ /** Capability Bit Map : DSS OFDM */
+ t_u8 dsss_ofdm:1;
+ /** Capability Bit Map : Reserved */
+ t_u8 rsrvd1:2;
+} MLAN_PACK_END IEEEtypes_CapInfo_t, *pIEEEtypes_CapInfo_t;
+#endif /* BIG_ENDIAN_SUPPORT */
+
+/** IEEEtypes_CfParamSet_t */
+typedef MLAN_PACK_START struct _IEEEtypes_CfParamSet_t
+{
+ /** CF peremeter : Element ID */
+ t_u8 element_id;
+ /** CF peremeter : Length */
+ t_u8 len;
+ /** CF peremeter : Count */
+ t_u8 cfp_cnt;
+ /** CF peremeter : Period */
+ t_u8 cfp_period;
+ /** CF peremeter : Maximum duration */
+ t_u16 cfp_max_duration;
+ /** CF peremeter : Remaining duration */
+ t_u16 cfp_duration_remaining;
+} MLAN_PACK_END IEEEtypes_CfParamSet_t, *pIEEEtypes_CfParamSet_t;
+
+/** IEEEtypes_IbssParamSet_t */
+typedef MLAN_PACK_START struct _IEEEtypes_IbssParamSet_t
+{
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+ /** ATIM window value in milliseconds */
+ t_u16 atim_window;
+} MLAN_PACK_END IEEEtypes_IbssParamSet_t, *pIEEEtypes_IbssParamSet_t;
+
+/** IEEEtypes_SsParamSet_t */
+typedef MLAN_PACK_START union _IEEEtypes_SsParamSet_t
+{
+ /** SS parameter : CF parameter set */
+ IEEEtypes_CfParamSet_t cf_param_set;
+ /** SS parameter : IBSS parameter set */
+ IEEEtypes_IbssParamSet_t ibss_param_set;
+} MLAN_PACK_END IEEEtypes_SsParamSet_t, *pIEEEtypes_SsParamSet_t;
+
+/** IEEEtypes_FhParamSet_t */
+typedef MLAN_PACK_START struct _IEEEtypes_FhParamSet_t
+{
+ /** FH parameter : Element ID */
+ t_u8 element_id;
+ /** FH parameter : Length */
+ t_u8 len;
+ /** FH parameter : Dwell time in milliseconds */
+ t_u16 dwell_time;
+ /** FH parameter : Hop set */
+ t_u8 hop_set;
+ /** FH parameter : Hop pattern */
+ t_u8 hop_pattern;
+ /** FH parameter : Hop index */
+ t_u8 hop_index;
+} MLAN_PACK_END IEEEtypes_FhParamSet_t, *pIEEEtypes_FhParamSet_t;
+
+/** IEEEtypes_DsParamSet_t */
+typedef MLAN_PACK_START struct _IEEEtypes_DsParamSet_t
+{
+ /** DS parameter : Element ID */
+ t_u8 element_id;
+ /** DS parameter : Length */
+ t_u8 len;
+ /** DS parameter : Current channel */
+ t_u8 current_chan;
+} MLAN_PACK_END IEEEtypes_DsParamSet_t, *pIEEEtypes_DsParamSet_t;
+
+/** IEEEtypes_PhyParamSet_t */
+typedef MLAN_PACK_START union _IEEEtypes_PhyParamSet_t
+{
+ /** FH parameter set */
+ IEEEtypes_FhParamSet_t fh_param_set;
+ /** DS parameter set */
+ IEEEtypes_DsParamSet_t ds_param_set;
+} MLAN_PACK_END IEEEtypes_PhyParamSet_t, *pIEEEtypes_PhyParamSet_t;
+
+/** IEEEtypes_ERPInfo_t */
+typedef MLAN_PACK_START struct _IEEEtypes_ERPInfo_t
+{
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+ /** ERP flags */
+ t_u8 erp_flags;
+} MLAN_PACK_END IEEEtypes_ERPInfo_t, *pIEEEtypes_ERPInfo_t;
+
+/** IEEEtypes_AId_t */
+typedef t_u16 IEEEtypes_AId_t;
+
+/** IEEEtypes_StatusCode_t */
+typedef t_u16 IEEEtypes_StatusCode_t;
+
+/** IEEEtypes_AssocRsp_t */
+typedef MLAN_PACK_START struct _IEEEtypes_AssocRsp_t
+{
+ /** Capability information */
+ IEEEtypes_CapInfo_t capability;
+ /** Association response status code */
+ IEEEtypes_StatusCode_t status_code;
+ /** Association ID */
+ IEEEtypes_AId_t a_id;
+ /** IE data buffer */
+ t_u8 ie_buffer[1];
+} MLAN_PACK_END IEEEtypes_AssocRsp_t, *pIEEEtypes_AssocRsp_t;
+
+/** 802.11 supported rates */
+typedef t_u8 WLAN_802_11_RATES[WLAN_SUPPORTED_RATES];
+
+/** cipher TKIP */
+#define WPA_CIPHER_TKIP 2
+/** cipher AES */
+#define WPA_CIPHER_AES_CCM 4
+/** AKM: 8021x */
+#define RSN_AKM_8021X 1
+/** AKM: PSK */
+#define RSN_AKM_PSK 2
+
+/** wpa_suite_t */
+typedef MLAN_PACK_START struct _wpa_suite_t
+{
+ /** OUI */
+ t_u8 oui[3];
+ /** tyep */
+ t_u8 type;
+} MLAN_PACK_END wpa_suite, wpa_suite_mcast_t;
+
+/** wpa_suite_ucast_t */
+typedef MLAN_PACK_START struct
+{
+ /* count */
+ t_u16 count;
+ /** wpa_suite list */
+ wpa_suite list[1];
+} MLAN_PACK_END wpa_suite_ucast_t, wpa_suite_auth_key_mgmt_t;
+
+/** IEEEtypes_Rsn_t */
+typedef MLAN_PACK_START struct _IEEEtypes_Rsn_t
+{
+ /** Rsn : Element ID */
+ t_u8 element_id;
+ /** Rsn : Length */
+ t_u8 len;
+ /** Rsn : version */
+ t_u16 version;
+ /** Rsn : group cipher */
+ wpa_suite_mcast_t group_cipher;
+ /** Rsn : pairwise cipher */
+ wpa_suite_ucast_t pairwise_cipher;
+} MLAN_PACK_END IEEEtypes_Rsn_t, *pIEEEtypes_Rsn_t;
+
+/** IEEEtypes_Wpa_t */
+typedef MLAN_PACK_START struct _IEEEtypes_Wpa_t
+{
+ /** Wpa : Element ID */
+ t_u8 element_id;
+ /** Wpa : Length */
+ t_u8 len;
+ /** Wpa : oui */
+ t_u8 oui[4];
+ /** version */
+ t_u16 version;
+ /** Wpa : group cipher */
+ wpa_suite_mcast_t group_cipher;
+ /** Wpa : pairwise cipher */
+ wpa_suite_ucast_t pairwise_cipher;
+} MLAN_PACK_END IEEEtypes_Wpa_t, *pIEEEtypes_Wpa_t;
+
+/** Maximum number of AC QOS queues available in the driver/firmware */
+#define MAX_AC_QUEUES 4
+
+/** Data structure of WMM QoS information */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmQosInfo_t
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ /** QoS UAPSD */
+ t_u8 qos_uapsd:1;
+ /** Reserved */
+ t_u8 reserved:3;
+ /** Parameter set count */
+ t_u8 para_set_count:4;
+#else
+ /** Parameter set count */
+ t_u8 para_set_count:4;
+ /** Reserved */
+ t_u8 reserved:3;
+ /** QoS UAPSD */
+ t_u8 qos_uapsd:1;
+#endif /* BIG_ENDIAN_SUPPORT */
+} MLAN_PACK_END IEEEtypes_WmmQosInfo_t, *pIEEEtypes_WmmQosInfo_t;
+
+/** Data structure of WMM Aci/Aifsn */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmAciAifsn_t
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ /** Reserved */
+ t_u8 reserved:1;
+ /** Aci */
+ t_u8 aci:2;
+ /** Acm */
+ t_u8 acm:1;
+ /** Aifsn */
+ t_u8 aifsn:4;
+#else
+ /** Aifsn */
+ t_u8 aifsn:4;
+ /** Acm */
+ t_u8 acm:1;
+ /** Aci */
+ t_u8 aci:2;
+ /** Reserved */
+ t_u8 reserved:1;
+#endif /* BIG_ENDIAN_SUPPORT */
+} MLAN_PACK_END IEEEtypes_WmmAciAifsn_t, *pIEEEtypes_WmmAciAifsn_t;
+
+/** Data structure of WMM ECW */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmEcw_t
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ /** Maximum Ecw */
+ t_u8 ecw_max:4;
+ /** Minimum Ecw */
+ t_u8 ecw_min:4;
+#else
+ /** Minimum Ecw */
+ t_u8 ecw_min:4;
+ /** Maximum Ecw */
+ t_u8 ecw_max:4;
+#endif /* BIG_ENDIAN_SUPPORT */
+} MLAN_PACK_END IEEEtypes_WmmEcw_t, *pIEEEtypes_WmmEcw_t;
+
+/** Data structure of WMM AC parameters */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmAcParameters_t
+{
+ IEEEtypes_WmmAciAifsn_t aci_aifsn; /**< AciAifSn */
+ IEEEtypes_WmmEcw_t ecw; /**< Ecw */
+ t_u16 tx_op_limit; /**< Tx op limit */
+} MLAN_PACK_END IEEEtypes_WmmAcParameters_t, *pIEEEtypes_WmmAcParameters_t;
+
+/** Data structure of WMM Info IE */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmInfo_t
+{
+
+ /**
+ * WMM Info IE - Vendor Specific Header:
+ * element_id [221/0xdd]
+ * Len [7]
+ * Oui [00:50:f2]
+ * OuiType [2]
+ * OuiSubType [0]
+ * Version [1]
+ */
+ IEEEtypes_VendorHeader_t vend_hdr;
+
+ /** QoS information */
+ IEEEtypes_WmmQosInfo_t qos_info;
+
+} MLAN_PACK_END IEEEtypes_WmmInfo_t, *pIEEEtypes_WmmInfo_t;
+
+/** Data structure of WMM parameter IE */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmParameter_t
+{
+ /**
+ * WMM Parameter IE - Vendor Specific Header:
+ * element_id [221/0xdd]
+ * Len [24]
+ * Oui [00:50:f2]
+ * OuiType [2]
+ * OuiSubType [1]
+ * Version [1]
+ */
+ IEEEtypes_VendorHeader_t vend_hdr;
+
+ /** QoS information */
+ IEEEtypes_WmmQosInfo_t qos_info;
+ /** Reserved */
+ t_u8 reserved;
+
+ /** AC Parameters Record WMM_AC_BE, WMM_AC_BK, WMM_AC_VI, WMM_AC_VO */
+ IEEEtypes_WmmAcParameters_t ac_params[MAX_AC_QUEUES];
+} MLAN_PACK_END IEEEtypes_WmmParameter_t, *pIEEEtypes_WmmParameter_t;
+
+/** Enumerator for TSPEC direction */
+typedef MLAN_PACK_START enum _IEEEtypes_WMM_TSPEC_TS_Info_Direction_e
+{
+
+ TSPEC_DIR_UPLINK = 0,
+ TSPEC_DIR_DOWNLINK = 1,
+ /* 2 is a reserved value */
+ TSPEC_DIR_BIDIRECT = 3,
+
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_TS_Info_Direction_e;
+
+/** Enumerator for TSPEC PSB */
+typedef MLAN_PACK_START enum _IEEEtypes_WMM_TSPEC_TS_Info_PSB_e
+{
+
+ TSPEC_PSB_LEGACY = 0,
+ TSPEC_PSB_TRIG = 1,
+
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_TS_Info_PSB_e;
+
+/** Enumerator for TSPEC Ack Policy */
+typedef MLAN_PACK_START enum _IEEEtypes_WMM_TSPEC_TS_Info_AckPolicy_e
+{
+
+ TSPEC_ACKPOLICY_NORMAL = 0,
+ TSPEC_ACKPOLICY_NOACK = 1,
+ /* 2 is reserved */
+ TSPEC_ACKPOLICY_BLOCKACK = 3,
+
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_TS_Info_AckPolicy_e;
+
+/** Enumerator for TSPEC Trafffice type */
+typedef MLAN_PACK_START enum _IEEEtypes_WMM_TSPEC_TS_TRAFFIC_TYPE_e
+{
+
+ TSPEC_TRAFFIC_APERIODIC = 0,
+ TSPEC_TRAFFIC_PERIODIC = 1,
+
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_TS_TRAFFIC_TYPE_e;
+
+/** Data structure of WMM TSPEC information */
+typedef MLAN_PACK_START struct
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ t_u8 Reserved17_23:7; // ! Reserved
+ t_u8 Schedule:1;
+ IEEEtypes_WMM_TSPEC_TS_Info_AckPolicy_e AckPolicy:2;
+ t_u8 UserPri:3; // ! 802.1d User Priority
+ IEEEtypes_WMM_TSPEC_TS_Info_PSB_e PowerSaveBehavior:1; // !
+ // Legacy/Trigg
+ t_u8 Aggregation:1; // ! Reserved
+ t_u8 AccessPolicy2:1; // !
+ t_u8 AccessPolicy1:1; // !
+ IEEEtypes_WMM_TSPEC_TS_Info_Direction_e Direction:2;
+ t_u8 TID:4; // ! Unique identifier
+ IEEEtypes_WMM_TSPEC_TS_TRAFFIC_TYPE_e TrafficType:1;
+#else
+ IEEEtypes_WMM_TSPEC_TS_TRAFFIC_TYPE_e TrafficType:1;
+ t_u8 TID:4; // ! Unique identifier
+ IEEEtypes_WMM_TSPEC_TS_Info_Direction_e Direction:2;
+ t_u8 AccessPolicy1:1; // !
+ t_u8 AccessPolicy2:1; // !
+ t_u8 Aggregation:1; // ! Reserved
+ IEEEtypes_WMM_TSPEC_TS_Info_PSB_e PowerSaveBehavior:1; // !
+ // Legacy/Trigg
+ t_u8 UserPri:3; // ! 802.1d User Priority
+ IEEEtypes_WMM_TSPEC_TS_Info_AckPolicy_e AckPolicy:2;
+ t_u8 Schedule:1;
+ t_u8 Reserved17_23:7; // ! Reserved
+#endif
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_TS_Info_t;
+
+/** Data structure of WMM TSPEC Nominal Size */
+typedef MLAN_PACK_START struct
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ t_u16 Fixed:1; // ! 1: Fixed size given in Size, 0: Var, size
+ // is nominal
+ t_u16 Size:15; // ! Nominal size in octets
+#else
+ t_u16 Size:15; // ! Nominal size in octets
+ t_u16 Fixed:1; // ! 1: Fixed size given in Size, 0: Var, size
+ // is nominal
+#endif
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_NomMSDUSize_t;
+
+/** Data structure of WMM TSPEC SBWA */
+typedef MLAN_PACK_START struct
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ t_u16 Whole:3; // ! Whole portion
+ t_u16 Fractional:13; // ! Fractional portion
+#else
+ t_u16 Fractional:13; // ! Fractional portion
+ t_u16 Whole:3; // ! Whole portion
+#endif
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_SBWA;
+
+/** Data structure of WMM TSPEC Body */
+typedef MLAN_PACK_START struct
+{
+
+ IEEEtypes_WMM_TSPEC_TS_Info_t TSInfo;
+ IEEEtypes_WMM_TSPEC_NomMSDUSize_t NomMSDUSize;
+ t_u16 MaximumMSDUSize;
+ t_u32 MinServiceInterval;
+ t_u32 MaxServiceInterval;
+ t_u32 InactivityInterval;
+ t_u32 SuspensionInterval;
+ t_u32 ServiceStartTime;
+ t_u32 MinimumDataRate;
+ t_u32 MeanDataRate;
+ t_u32 PeakDataRate;
+ t_u32 MaxBurstSize;
+ t_u32 DelayBound;
+ t_u32 MinPHYRate;
+ IEEEtypes_WMM_TSPEC_SBWA SurplusBWAllowance;
+ t_u16 MediumTime;
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_Body_t;
+
+/** Data structure of WMM TSPEC all elements */
+typedef MLAN_PACK_START struct
+{
+ t_u8 ElementId;
+ t_u8 Len;
+ t_u8 OuiType[4]; /* 00:50:f2:02 */
+ t_u8 OuiSubType; /* 01 */
+ t_u8 Version;
+
+ IEEEtypes_WMM_TSPEC_Body_t TspecBody;
+
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_t;
+
+/** WMM Action Category values */
+typedef MLAN_PACK_START enum _IEEEtypes_ActionCategory_e
+{
+
+ IEEE_MGMT_ACTION_CATEGORY_SPECTRUM_MGMT = 0,
+ IEEE_MGMT_ACTION_CATEGORY_QOS = 1,
+ IEEE_MGMT_ACTION_CATEGORY_DLS = 2,
+ IEEE_MGMT_ACTION_CATEGORY_BLOCK_ACK = 3,
+ IEEE_MGMT_ACTION_CATEGORY_PUBLIC = 4,
+ IEEE_MGMT_ACTION_CATEGORY_RADIO_RSRC = 5,
+ IEEE_MGMT_ACTION_CATEGORY_FAST_BSS_TRANS = 6,
+ IEEE_MGMT_ACTION_CATEGORY_HT = 7,
+
+ IEEE_MGMT_ACTION_CATEGORY_WNM = 10,
+ IEEE_MGMT_ACTION_CATEGORY_UNPROTECT_WNM = 11,
+
+ IEEE_MGMT_ACTION_CATEGORY_WMM_TSPEC = 17
+} MLAN_PACK_END IEEEtypes_ActionCategory_e;
+
+/** WMM TSPEC operations */
+typedef MLAN_PACK_START enum _IEEEtypes_WMM_Tspec_Action_e
+{
+
+ TSPEC_ACTION_CODE_ADDTS_REQ = 0,
+ TSPEC_ACTION_CODE_ADDTS_RSP = 1,
+ TSPEC_ACTION_CODE_DELTS = 2,
+
+} MLAN_PACK_END IEEEtypes_WMM_Tspec_Action_e;
+
+/** WMM TSPEC Category Action Base */
+typedef MLAN_PACK_START struct
+{
+
+ IEEEtypes_ActionCategory_e category;
+ IEEEtypes_WMM_Tspec_Action_e action;
+ t_u8 dialogToken;
+
+} MLAN_PACK_END IEEEtypes_WMM_Tspec_Action_Base_Tspec_t;
+
+/** WMM TSPEC AddTS request structure */
+typedef MLAN_PACK_START struct
+{
+
+ IEEEtypes_WMM_Tspec_Action_Base_Tspec_t tspecAct;
+ t_u8 statusCode;
+ IEEEtypes_WMM_TSPEC_t tspecIE;
+
+ /* Place holder for additional elements after the TSPEC */
+ t_u8 subElem[256];
+
+} MLAN_PACK_END IEEEtypes_Action_WMM_AddTsReq_t;
+
+/** WMM TSPEC AddTS response structure */
+typedef MLAN_PACK_START struct
+{
+ IEEEtypes_WMM_Tspec_Action_Base_Tspec_t tspecAct;
+ t_u8 statusCode;
+ IEEEtypes_WMM_TSPEC_t tspecIE;
+
+ /* Place holder for additional elements after the TSPEC */
+ t_u8 subElem[256];
+
+} MLAN_PACK_END IEEEtypes_Action_WMM_AddTsRsp_t;
+
+/** WMM TSPEC DelTS structure */
+typedef MLAN_PACK_START struct
+{
+ IEEEtypes_WMM_Tspec_Action_Base_Tspec_t tspecAct;
+ t_u8 reasonCode;
+ IEEEtypes_WMM_TSPEC_t tspecIE;
+
+} MLAN_PACK_END IEEEtypes_Action_WMM_DelTs_t;
+
+/** union of WMM TSPEC structures */
+typedef MLAN_PACK_START union
+{
+ IEEEtypes_WMM_Tspec_Action_Base_Tspec_t tspecAct;
+
+ IEEEtypes_Action_WMM_AddTsReq_t addTsReq;
+ IEEEtypes_Action_WMM_AddTsRsp_t addTsRsp;
+ IEEEtypes_Action_WMM_DelTs_t delTs;
+
+} MLAN_PACK_END IEEEtypes_Action_WMMAC_t;
+
+/** union of WMM TSPEC & Action category */
+typedef MLAN_PACK_START union
+{
+ IEEEtypes_ActionCategory_e category;
+
+ IEEEtypes_Action_WMMAC_t wmmAc;
+
+} MLAN_PACK_END IEEEtypes_ActionFrame_t;
+
+/** Data structure for subband set */
+typedef MLAN_PACK_START struct _IEEEtypes_SubbandSet_t
+{
+ /** First channel */
+ t_u8 first_chan;
+ /** Number of channels */
+ t_u8 no_of_chan;
+ /** Maximum Tx power in dBm */
+ t_u8 max_tx_pwr;
+} MLAN_PACK_END IEEEtypes_SubbandSet_t, *pIEEEtypes_SubbandSet_t;
+
+#ifdef STA_SUPPORT
+/** Data structure for Country IE */
+typedef MLAN_PACK_START struct _IEEEtypes_CountryInfoSet_t
+{
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+ /** Country code */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ /** Set of subbands */
+ IEEEtypes_SubbandSet_t sub_band[1];
+} MLAN_PACK_END IEEEtypes_CountryInfoSet_t, *pIEEEtypes_CountryInfoSet_t;
+
+/** Data structure for Country IE full set */
+typedef MLAN_PACK_START struct _IEEEtypes_CountryInfoFullSet_t
+{
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+ /** Country code */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ /** Set of subbands */
+ IEEEtypes_SubbandSet_t sub_band[MRVDRV_MAX_SUBBAND_802_11D];
+} MLAN_PACK_END IEEEtypes_CountryInfoFullSet_t,
+ *pIEEEtypes_CountryInfoFullSet_t;
+
+#endif /* STA_SUPPORT */
+
+/** HT Capabilities Data */
+typedef struct MLAN_PACK_START _HTCap_t
+{
+ /** HT Capabilities Info field */
+ t_u16 ht_cap_info;
+ /** A-MPDU Parameters field */
+ t_u8 ampdu_param;
+ /** Supported MCS Set field */
+ t_u8 supported_mcs_set[16];
+ /** HT Extended Capabilities field */
+ t_u16 ht_ext_cap;
+ /** Transmit Beamforming Capabilities field */
+ t_u32 tx_bf_cap;
+ /** Antenna Selection Capability field */
+ t_u8 asel;
+} MLAN_PACK_END HTCap_t, *pHTCap_t;
+
+/** HT Information Data */
+typedef struct MLAN_PACK_START _HTInfo_t
+{
+ /** Primary channel */
+ t_u8 pri_chan;
+ /** Field 2 */
+ t_u8 field2;
+ /** Field 3 */
+ t_u16 field3;
+ /** Field 4 */
+ t_u16 field4;
+ /** Bitmap indicating MCSs supported by all HT STAs in the BSS */
+ t_u8 basic_mcs_set[16];
+} MLAN_PACK_END HTInfo_t, *pHTInfo_t;
+
+/** 20/40 BSS Coexistence Data */
+typedef struct MLAN_PACK_START _BSSCo2040_t
+{
+ /** 20/40 BSS Coexistence value */
+ t_u8 bss_co_2040_value;
+} MLAN_PACK_END BSSCo2040_t, *pBSSCo2040_t;
+
+/** Extended Capabilities Data */
+typedef struct MLAN_PACK_START _ExtCap_t
+{
+ /** Extended Capabilities value */
+ t_u8 ext_cap_value;
+} MLAN_PACK_END ExtCap_t, *pExtCap_t;
+
+/** Overlapping BSS Scan Parameters Data */
+typedef struct MLAN_PACK_START _OverlapBSSScanParam_t
+{
+ /** OBSS Scan Passive Dwell in milliseconds */
+ t_u16 obss_scan_passive_dwell;
+ /** OBSS Scan Active Dwell in milliseconds */
+ t_u16 obss_scan_active_dwell;
+ /** BSS Channel Width Trigger Scan Interval in seconds */
+ t_u16 bss_chan_width_trigger_scan_int;
+ /** OBSS Scan Passive Total Per Channel */
+ t_u16 obss_scan_passive_total;
+ /** OBSS Scan Active Total Per Channel */
+ t_u16 obss_scan_active_total;
+ /** BSS Width Channel Transition Delay Factor */
+ t_u16 bss_width_chan_trans_delay;
+ /** OBSS Scan Activity Threshold */
+ t_u16 obss_scan_active_threshold;
+} MLAN_PACK_END OBSSScanParam_t, *pOBSSScanParam_t;
+
+/** HT Capabilities IE */
+typedef MLAN_PACK_START struct _IEEEtypes_HTCap_t
+{
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** HTCap struct */
+ HTCap_t ht_cap;
+} MLAN_PACK_END IEEEtypes_HTCap_t, *pIEEEtypes_HTCap_t;
+
+/** HT Information IE */
+typedef MLAN_PACK_START struct _IEEEtypes_HTInfo_t
+{
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** HTInfo struct */
+ HTInfo_t ht_info;
+} MLAN_PACK_END IEEEtypes_HTInfo_t, *pIEEEtypes_HTInfo_t;
+
+/** 20/40 BSS Coexistence IE */
+typedef MLAN_PACK_START struct _IEEEtypes_2040BSSCo_t
+{
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** BSSCo2040_t struct */
+ BSSCo2040_t bss_co_2040;
+} MLAN_PACK_END IEEEtypes_2040BSSCo_t, *pIEEEtypes_2040BSSCo_t;
+
+/** Extended Capabilities IE */
+typedef MLAN_PACK_START struct _IEEEtypes_ExtCap_t
+{
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** ExtCap_t struct */
+ ExtCap_t ext_cap;
+} MLAN_PACK_END IEEEtypes_ExtCap_t, *pIEEEtypes_ExtCap_t;
+
+/** Overlapping BSS Scan Parameters IE */
+typedef MLAN_PACK_START struct _IEEEtypes_OverlapBSSScanParam_t
+{
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** OBSSScanParam_t struct */
+ OBSSScanParam_t obss_scan_param;
+} MLAN_PACK_END IEEEtypes_OverlapBSSScanParam_t,
+ *pIEEEtypes_OverlapBSSScanParam_t;
+
+/** Maximum number of subbands in the IEEEtypes_SupportedChannels_t structure */
+#define WLAN_11H_MAX_SUBBANDS 5
+
+/** Maximum number of DFS channels configured in IEEEtypes_IBSS_DFS_t */
+#define WLAN_11H_MAX_IBSS_DFS_CHANNELS 25
+
+/** IEEE Power Constraint element (7.3.2.15) */
+typedef MLAN_PACK_START struct
+{
+ t_u8 element_id; /**< IEEE Element ID = 32 */
+ t_u8 len; /**< Element length after id and len */
+ t_u8 local_constraint; /**< Local power constraint applied to 11d chan info */
+} MLAN_PACK_END IEEEtypes_PowerConstraint_t;
+
+/** IEEE Power Capability element (7.3.2.16) */
+typedef MLAN_PACK_START struct
+{
+ t_u8 element_id; /**< IEEE Element ID = 33 */
+ t_u8 len; /**< Element length after id and len */
+ t_s8 min_tx_power_capability; /**< Minimum Transmit power (dBm) */
+ t_s8 max_tx_power_capability; /**< Maximum Transmit power (dBm) */
+} MLAN_PACK_END IEEEtypes_PowerCapability_t;
+
+/** IEEE TPC Report element (7.3.2.18) */
+typedef MLAN_PACK_START struct
+{
+ t_u8 element_id; /**< IEEE Element ID = 35 */
+ t_u8 len; /**< Element length after id and len */
+ t_s8 tx_power; /**< Max power used to transmit the TPC Report frame (dBm) */
+ t_s8 link_margin; /**< Link margin when TPC Request received (dB) */
+} MLAN_PACK_END IEEEtypes_TPCReport_t;
+
+/* IEEE Supported Channel sub-band description (7.3.2.19) */
+/**
+ * Sub-band description used in the supported channels element.
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 start_chan; /**< Starting channel in the subband */
+ t_u8 num_chans; /**< Number of channels in the subband */
+
+} MLAN_PACK_END IEEEtypes_SupportChan_Subband_t;
+
+/* IEEE Supported Channel element (7.3.2.19) */
+/**
+ * Sent in association requests. Details the sub-bands and number
+ * of channels supported in each subband
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 element_id; /**< IEEE Element ID = 36 */
+ t_u8 len; /**< Element length after id and len */
+
+ /** Configured sub-bands information in the element */
+ IEEEtypes_SupportChan_Subband_t subband[WLAN_11H_MAX_SUBBANDS];
+
+} MLAN_PACK_END IEEEtypes_SupportedChannels_t;
+
+/* IEEE Channel Switch Announcement Element (7.3.2.20) */
+/**
+ * Provided in beacons and probe responses. Used to advertise when
+ * and to which channel it is changing to. Only starting STAs in
+ * an IBSS and APs are allowed to originate a chan switch element.
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 element_id; /**< IEEE Element ID = 37 */
+ t_u8 len; /**< Element length after id and len */
+ t_u8 chan_switch_mode; /**< STA should not transmit any frames if 1 */
+ t_u8 new_channel_num; /**< Channel # that AP/IBSS is moving to */
+ t_u8 chan_switch_count; /**< # of TBTTs before channel switch */
+
+} MLAN_PACK_END IEEEtypes_ChanSwitchAnn_t;
+
+/* IEEE Quiet Period Element (7.3.2.23) */
+/**
+ * Provided in beacons and probe responses. Indicates times during
+ * which the STA should not be transmitting data. Only starting STAs in
+ * an IBSS and APs are allowed to originate a quiet element.
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 element_id; /**< IEEE Element ID = 40 */
+ t_u8 len; /**< Element length after id and len */
+ t_u8 quiet_count; /**< Number of TBTTs until beacon with the quiet period */
+ t_u8 quiet_period; /**< Regular quiet period, # of TBTTS between periods */
+ t_u16 quiet_duration; /**< Duration of the quiet period in TUs */
+ t_u16 quiet_offset; /**< Offset in TUs from the TBTT for the quiet period */
+
+} MLAN_PACK_END IEEEtypes_Quiet_t;
+
+/**
+*** @brief Map octet of the basic measurement report (7.3.2.22.1)
+**/
+typedef MLAN_PACK_START struct
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ t_u8 rsvd5_7:3; /**< Reserved */
+ t_u8 unmeasured:1; /**< Channel is unmeasured */
+ t_u8 radar:1; /**< Radar detected on channel */
+ t_u8 unidentified_sig:1; /**< Unidentified signal found on channel */
+ t_u8 ofdm_preamble:1; /**< OFDM preamble detected on channel */
+ t_u8 bss:1; /**< At least one valid MPDU received on channel */
+#else
+ t_u8 bss:1; /**< At least one valid MPDU received on channel */
+ t_u8 ofdm_preamble:1; /**< OFDM preamble detected on channel */
+ t_u8 unidentified_sig:1; /**< Unidentified signal found on channel */
+ t_u8 radar:1; /**< Radar detected on channel */
+ t_u8 unmeasured:1; /**< Channel is unmeasured */
+ t_u8 rsvd5_7:3; /**< Reserved */
+#endif /* BIG_ENDIAN_SUPPORT */
+
+} MLAN_PACK_END MeasRptBasicMap_t;
+
+/* IEEE DFS Channel Map field (7.3.2.24) */
+/**
+ * Used to list supported channels and provide a octet "map" field which
+ * contains a basic measurement report for that channel in the
+ * IEEEtypes_IBSS_DFS_t element
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 channel_number; /**< Channel number */
+ MeasRptBasicMap_t rpt_map; /**< Basic measurement report for the channel */
+
+} MLAN_PACK_END IEEEtypes_ChannelMap_t;
+
+/* IEEE IBSS DFS Element (7.3.2.24) */
+/**
+ * IBSS DFS element included in ad hoc beacons and probe responses.
+ * Provides information regarding the IBSS DFS Owner as well as the
+ * originating STAs supported channels and basic measurement results.
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 element_id; /**< IEEE Element ID = 41 */
+ t_u8 len; /**< Element length after id and len */
+ t_u8 dfs_owner[MLAN_MAC_ADDR_LENGTH]; /**< DFS Owner STA Address */
+ t_u8 dfs_recovery_interval; /**< DFS Recovery time in TBTTs */
+
+ /** Variable length map field, one Map entry for each supported channel */
+ IEEEtypes_ChannelMap_t channel_map[WLAN_11H_MAX_IBSS_DFS_CHANNELS];
+
+} MLAN_PACK_END IEEEtypes_IBSS_DFS_t;
+
+/* 802.11h BSS information kept for each BSSID received in scan results */
+/**
+ * IEEE BSS information needed from scan results for later processing in
+ * join commands
+ */
+typedef struct
+{
+ t_u8 sensed_11h; /**< Capability bit set or 11h IE found in this BSS */
+
+ IEEEtypes_PowerConstraint_t power_constraint; /**< Power Constraint IE */
+ IEEEtypes_PowerCapability_t power_capability; /**< Power Capability IE */
+ IEEEtypes_TPCReport_t tpc_report; /**< TPC Report IE */
+ IEEEtypes_ChanSwitchAnn_t chan_switch_ann; /**< Channel Switch Announcement IE */
+ IEEEtypes_Quiet_t quiet; /**< Quiet IE */
+ IEEEtypes_IBSS_DFS_t ibss_dfs; /**< IBSS DFS Element IE */
+
+} wlan_11h_bss_info_t;
+
+#ifdef STA_SUPPORT
+/** Macro for maximum size of scan response buffer */
+#define MAX_SCAN_RSP_BUF (16 * 1024)
+
+/** Maximum number of channels that can be sent in user scan config */
+#define WLAN_USER_SCAN_CHAN_MAX 50
+
+/** Maximum length of SSID list */
+#define MRVDRV_MAX_SSID_LIST_LENGTH 10
+
+/** Scan all the channels in specified band */
+#define BAND_SPECIFIED 0x80
+
+/**
+ * IOCTL SSID List sub-structure sent in wlan_ioctl_user_scan_cfg
+ *
+ * Used to specify SSID specific filters as well as SSID pattern matching
+ * filters for scan result processing in firmware.
+ */
+typedef MLAN_PACK_START struct _wlan_user_scan_ssid
+{
+ /** SSID */
+ t_u8 ssid[MLAN_MAX_SSID_LENGTH + 1];
+ /** Maximum length of SSID */
+ t_u8 max_len;
+} MLAN_PACK_END wlan_user_scan_ssid;
+
+/**
+ * @brief IOCTL channel sub-structure sent in wlan_ioctl_user_scan_cfg
+ *
+ * Multiple instances of this structure are included in the IOCTL command
+ * to configure a instance of a scan on the specific channel.
+ */
+typedef MLAN_PACK_START struct _wlan_user_scan_chan
+{
+ /** Channel Number to scan */
+ t_u8 chan_number;
+ /** Radio type: 'B/G' Band = 0, 'A' Band = 1 */
+ t_u8 radio_type;
+ /** Scan type: Active = 1, Passive = 2 */
+ t_u8 scan_type;
+ /** Reserved */
+ t_u8 reserved;
+ /** Scan duration in milliseconds; if 0 default used */
+ t_u32 scan_time;
+} MLAN_PACK_END wlan_user_scan_chan;
+
+/**
+ * Input structure to configure an immediate scan cmd to firmware
+ *
+ * Specifies a number of parameters to be used in general for the scan
+ * as well as a channel list (wlan_user_scan_chan) for each scan period
+ * desired.
+ */
+typedef MLAN_PACK_START struct
+{
+ /**
+ * Flag set to keep the previous scan table intact
+ *
+ * If set, the scan results will accumulate, replacing any previous
+ * matched entries for a BSS with the new scan data
+ */
+ t_u8 keep_previous_scan;
+ /**
+ * BSS mode to be sent in the firmware command
+ *
+ * Field can be used to restrict the types of networks returned in the
+ * scan. Valid settings are:
+ *
+ * - MLAN_SCAN_MODE_BSS (infrastructure)
+ * - MLAN_SCAN_MODE_IBSS (adhoc)
+ * - MLAN_SCAN_MODE_ANY (unrestricted, adhoc and infrastructure)
+ */
+ t_u8 bss_mode;
+ /**
+ * Configure the number of probe requests for active chan scans
+ */
+ t_u8 num_probes;
+ /**
+ * @brief Reserved
+ */
+ t_u8 reserved;
+ /**
+ * @brief BSSID filter sent in the firmware command to limit the results
+ */
+ t_u8 specific_bssid[MLAN_MAC_ADDR_LENGTH];
+ /**
+ * SSID filter list used in the to limit the scan results
+ */
+ wlan_user_scan_ssid ssid_list[MRVDRV_MAX_SSID_LIST_LENGTH];
+ /**
+ * Variable number (fixed maximum) of channels to scan up
+ */
+ wlan_user_scan_chan chan_list[WLAN_USER_SCAN_CHAN_MAX];
+} MLAN_PACK_END wlan_user_scan_cfg;
+
+/** Default scan interval in millisecond*/
+#define DEFAULT_BGSCAN_INTERVAL 30000
+
+/** action get all, except pps/uapsd config */
+#define BG_SCAN_ACT_GET 0x0000
+/** action set all, except pps/uapsd config */
+#define BG_SCAN_ACT_SET 0x0001
+/** action get pps/uapsd config */
+#define BG_SCAN_ACT_GET_PPS_UAPSD 0x0100
+/** action set pps/uapsd config */
+#define BG_SCAN_ACT_SET_PPS_UAPSD 0x0101
+/** action set all */
+#define BG_SCAN_ACT_SET_ALL 0xff01
+/** ssid match */
+#define BG_SCAN_SSID_MATCH 0x0001
+/** ssid match and RSSI exceeded */
+#define BG_SCAN_SSID_RSSI_MATCH 0x0004
+/** Maximum number of channels that can be sent in bg scan config */
+#define WLAN_BG_SCAN_CHAN_MAX 32
+
+/**
+ * Input structure to configure bs scan cmd to firmware
+ */
+typedef MLAN_PACK_START struct
+{
+ /** action */
+ t_u16 action;
+ /** enable/disable */
+ t_u8 enable;
+ /** BSS type:
+ * MLAN_SCAN_MODE_BSS (infrastructure)
+ * MLAN_SCAN_MODE_IBSS (adhoc)
+ * MLAN_SCAN_MODE_ANY (unrestricted, adhoc and infrastructure)
+ */
+ t_u8 bss_type;
+ /** number of channel scanned during each scan */
+ t_u8 chan_per_scan;
+ /** interval between consecutive scan */
+ t_u32 scan_interval;
+ /** bit 0: ssid match bit 1: ssid match and SNR exceeded
+ * bit 2: ssid match and RSSI exceeded
+ * bit 31: wait for all channel scan to complete to report scan result
+ */
+ t_u32 report_condition;
+ /* Configure the number of probe requests for active chan scans */
+ t_u8 num_probes;
+ /** RSSI threshold */
+ t_u8 rssi_threshold;
+ /** SNR threshold */
+ t_u8 snr_threshold;
+ /** repeat count */
+ t_u16 repeat_count;
+ /** SSID filter list used in the to limit the scan results */
+ wlan_user_scan_ssid ssid_list[MRVDRV_MAX_SSID_LIST_LENGTH];
+ /** Variable number (fixed maximum) of channels to scan up */
+ wlan_user_scan_chan chan_list[WLAN_BG_SCAN_CHAN_MAX];
+} MLAN_PACK_END wlan_bgscan_cfg;
+#endif /* STA_SUPPORT */
+
+#ifdef PRAGMA_PACK
+#pragma pack(pop)
+#endif
+
+/** BSSDescriptor_t
+ * Structure used to store information for beacon/probe response
+ */
+typedef struct _BSSDescriptor_t
+{
+ /** MAC address */
+ mlan_802_11_mac_addr mac_address;
+
+ /** SSID */
+ mlan_802_11_ssid ssid;
+
+ /** WEP encryption requirement */
+ t_u32 privacy;
+
+ /** Receive signal strength in dBm */
+ t_s32 rssi;
+
+ /** Channel */
+ t_u32 channel;
+
+ /** Freq */
+ t_u32 freq;
+
+ /** Beacon period */
+ t_u16 beacon_period;
+
+ /** ATIM window */
+ t_u32 atim_window;
+
+ /** ERP flags */
+ t_u8 erp_flags;
+
+ /** Type of network in use */
+ WLAN_802_11_NETWORK_TYPE network_type_use;
+
+ /** Network infrastructure mode */
+ t_u32 bss_mode;
+
+ /** Network supported rates */
+ WLAN_802_11_RATES supported_rates;
+
+ /** Supported data rates */
+ t_u8 data_rates[WLAN_SUPPORTED_RATES];
+
+ /** Network band.
+ * BAND_B(0x01): 'b' band
+ * BAND_G(0x02): 'g' band
+ * BAND_A(0X04): 'a' band
+ */
+ t_u16 bss_band;
+
+ /** TSF timestamp from the current firmware TSF */
+ t_u64 network_tsf;
+
+ /** TSF value included in the beacon/probe response */
+ t_u8 time_stamp[8];
+
+ /** PHY parameter set */
+ IEEEtypes_PhyParamSet_t phy_param_set;
+
+ /** SS parameter set */
+ IEEEtypes_SsParamSet_t ss_param_set;
+
+ /** Capability information */
+ IEEEtypes_CapInfo_t cap_info;
+
+ /** WMM IE */
+ IEEEtypes_WmmParameter_t wmm_ie;
+
+ /** 802.11h BSS information */
+ wlan_11h_bss_info_t wlan_11h_bss_info;
+
+ /** Indicate disabling 11n when associate with AP */
+ t_u8 disable_11n;
+ /** 802.11n BSS information */
+ /** HT Capabilities IE */
+ IEEEtypes_HTCap_t *pht_cap;
+ /** HT Capabilities Offset */
+ t_u16 ht_cap_offset;
+ /** HT Information IE */
+ IEEEtypes_HTInfo_t *pht_info;
+ /** HT Information Offset */
+ t_u16 ht_info_offset;
+ /** 20/40 BSS Coexistence IE */
+ IEEEtypes_2040BSSCo_t *pbss_co_2040;
+ /** 20/40 BSS Coexistence Offset */
+ t_u16 bss_co_2040_offset;
+ /** Extended Capabilities IE */
+ IEEEtypes_ExtCap_t *pext_cap;
+ /** Extended Capabilities Offset */
+ t_u16 ext_cap_offset;
+ /** Overlapping BSS Scan Parameters IE */
+ IEEEtypes_OverlapBSSScanParam_t *poverlap_bss_scan_param;
+ /** Overlapping BSS Scan Parameters Offset */
+ t_u16 overlap_bss_offset;
+
+#ifdef STA_SUPPORT
+ /** Country information set */
+ IEEEtypes_CountryInfoFullSet_t country_info;
+#endif /* STA_SUPPORT */
+
+ /** WPA IE */
+ IEEEtypes_VendorSpecific_t *pwpa_ie;
+ /** WPA IE offset in the beacon buffer */
+ t_u16 wpa_offset;
+ /** RSN IE */
+ IEEEtypes_Generic_t *prsn_ie;
+ /** RSN IE offset in the beacon buffer */
+ t_u16 rsn_offset;
+#ifdef STA_SUPPORT
+ /** WAPI IE */
+ IEEEtypes_Generic_t *pwapi_ie;
+ /** WAPI IE offset in the beacon buffer */
+ t_u16 wapi_offset;
+#endif
+
+ /** Pointer to the returned scan response */
+ t_u8 *pbeacon_buf;
+ /** Length of the stored scan response */
+ t_u32 beacon_buf_size;
+ /** Max allocated size for updated scan response */
+ t_u32 beacon_buf_size_max;
+
+} BSSDescriptor_t, *pBSSDescriptor_t;
+
+#endif /* !_MLAN_IEEE_H_ */
diff --git a/drivers/net/wireless/sd8797/mlinux/mlan_ioctl.h b/drivers/net/wireless/sd8797/mlinux/mlan_ioctl.h
new file mode 100644
index 000000000000..964de9197ffe
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/mlan_ioctl.h
@@ -0,0 +1,2981 @@
+/** @file mlan_ioctl.h
+ *
+ * @brief This file declares the IOCTL data structures and APIs.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+/******************************************************
+Change log:
+ 11/07/2008: initial version
+******************************************************/
+
+#ifndef _MLAN_IOCTL_H_
+#define _MLAN_IOCTL_H_
+
+/** Enumeration for IOCTL request ID */
+enum _mlan_ioctl_req_id
+{
+ /* Scan Group */
+ MLAN_IOCTL_SCAN = 0x00010000,
+ MLAN_OID_SCAN_NORMAL,
+ MLAN_OID_SCAN_SPECIFIC_SSID,
+ MLAN_OID_SCAN_USER_CONFIG,
+ MLAN_OID_SCAN_CONFIG,
+ MLAN_OID_SCAN_GET_CURRENT_BSS,
+ MLAN_OID_SCAN_CANCEL,
+ MLAN_OID_SCAN_TABLE_FLUSH,
+ MLAN_OID_SCAN_BGSCAN_CONFIG,
+ /* BSS Configuration Group */
+ MLAN_IOCTL_BSS = 0x00020000,
+ MLAN_OID_BSS_START,
+ MLAN_OID_BSS_STOP,
+ MLAN_OID_BSS_MODE,
+ MLAN_OID_BSS_CHANNEL,
+ MLAN_OID_BSS_CHANNEL_LIST,
+ MLAN_OID_BSS_MAC_ADDR,
+ MLAN_OID_BSS_MULTICAST_LIST,
+ MLAN_OID_BSS_FIND_BSS,
+ MLAN_OID_IBSS_BCN_INTERVAL,
+ MLAN_OID_IBSS_ATIM_WINDOW,
+ MLAN_OID_IBSS_CHANNEL,
+#ifdef UAP_SUPPORT
+ MLAN_OID_UAP_BSS_CONFIG,
+ MLAN_OID_UAP_DEAUTH_STA,
+ MLAN_OID_UAP_BSS_RESET,
+#endif
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ MLAN_OID_BSS_ROLE,
+#endif
+#ifdef WIFI_DIRECT_SUPPORT
+ MLAN_OID_WIFI_DIRECT_MODE,
+#endif
+
+ /* Radio Configuration Group */
+ MLAN_IOCTL_RADIO_CFG = 0x00030000,
+ MLAN_OID_RADIO_CTRL,
+ MLAN_OID_BAND_CFG,
+ MLAN_OID_ANT_CFG,
+#ifdef WIFI_DIRECT_SUPPORT
+ MLAN_OID_REMAIN_CHAN_CFG,
+#endif
+
+ /* SNMP MIB Group */
+ MLAN_IOCTL_SNMP_MIB = 0x00040000,
+ MLAN_OID_SNMP_MIB_RTS_THRESHOLD,
+ MLAN_OID_SNMP_MIB_FRAG_THRESHOLD,
+ MLAN_OID_SNMP_MIB_RETRY_COUNT,
+#if defined(UAP_SUPPORT)
+ MLAN_OID_SNMP_MIB_DOT11D,
+ MLAN_OID_SNMP_MIB_DOT11H,
+#endif
+ MLAN_OID_SNMP_MIB_DTIM_PERIOD,
+
+ /* Status Information Group */
+ MLAN_IOCTL_GET_INFO = 0x00050000,
+ MLAN_OID_GET_STATS,
+ MLAN_OID_GET_SIGNAL,
+ MLAN_OID_GET_FW_INFO,
+ MLAN_OID_GET_VER_EXT,
+ MLAN_OID_GET_BSS_INFO,
+ MLAN_OID_GET_DEBUG_INFO,
+#ifdef UAP_SUPPORT
+ MLAN_OID_UAP_STA_LIST,
+#endif
+
+ /* Security Configuration Group */
+ MLAN_IOCTL_SEC_CFG = 0x00060000,
+ MLAN_OID_SEC_CFG_AUTH_MODE,
+ MLAN_OID_SEC_CFG_ENCRYPT_MODE,
+ MLAN_OID_SEC_CFG_WPA_ENABLED,
+ MLAN_OID_SEC_CFG_ENCRYPT_KEY,
+ MLAN_OID_SEC_CFG_PASSPHRASE,
+ MLAN_OID_SEC_CFG_EWPA_ENABLED,
+ MLAN_OID_SEC_CFG_ESUPP_MODE,
+ MLAN_OID_SEC_CFG_WAPI_ENABLED,
+ MLAN_OID_SEC_CFG_PORT_CTRL_ENABLED,
+
+ /* Rate Group */
+ MLAN_IOCTL_RATE = 0x00070000,
+ MLAN_OID_RATE_CFG,
+ MLAN_OID_GET_DATA_RATE,
+ MLAN_OID_SUPPORTED_RATES,
+
+ /* Power Configuration Group */
+ MLAN_IOCTL_POWER_CFG = 0x00080000,
+ MLAN_OID_POWER_CFG,
+ MLAN_OID_POWER_CFG_EXT,
+
+ /* Power Management Configuration Group */
+ MLAN_IOCTL_PM_CFG = 0x00090000,
+ MLAN_OID_PM_CFG_IEEE_PS,
+ MLAN_OID_PM_CFG_HS_CFG,
+ MLAN_OID_PM_CFG_INACTIVITY_TO,
+ MLAN_OID_PM_CFG_DEEP_SLEEP,
+ MLAN_OID_PM_CFG_SLEEP_PD,
+ MLAN_OID_PM_CFG_PS_CFG,
+ MLAN_OID_PM_CFG_SLEEP_PARAMS,
+#ifdef UAP_SUPPORT
+ MLAN_OID_PM_CFG_PS_MODE,
+#endif /* UAP_SUPPORT */
+ MLAN_OID_PM_INFO,
+
+ /* WMM Configuration Group */
+ MLAN_IOCTL_WMM_CFG = 0x000A0000,
+ MLAN_OID_WMM_CFG_ENABLE,
+ MLAN_OID_WMM_CFG_QOS,
+ MLAN_OID_WMM_CFG_ADDTS,
+ MLAN_OID_WMM_CFG_DELTS,
+ MLAN_OID_WMM_CFG_QUEUE_CONFIG,
+ MLAN_OID_WMM_CFG_QUEUE_STATS,
+ MLAN_OID_WMM_CFG_QUEUE_STATUS,
+ MLAN_OID_WMM_CFG_TS_STATUS,
+
+ /* WPS Configuration Group */
+ MLAN_IOCTL_WPS_CFG = 0x000B0000,
+ MLAN_OID_WPS_CFG_SESSION,
+
+ /* 802.11n Configuration Group */
+ MLAN_IOCTL_11N_CFG = 0x000C0000,
+ MLAN_OID_11N_CFG_TX,
+ MLAN_OID_11N_HTCAP_CFG,
+ MLAN_OID_11N_CFG_ADDBA_REJECT,
+ MLAN_OID_11N_CFG_AGGR_PRIO_TBL,
+ MLAN_OID_11N_CFG_ADDBA_PARAM,
+ MLAN_OID_11N_CFG_MAX_TX_BUF_SIZE,
+ MLAN_OID_11N_CFG_AMSDU_AGGR_CTRL,
+ MLAN_OID_11N_CFG_SUPPORTED_MCS_SET,
+ MLAN_OID_11N_CFG_TX_BF_CAP,
+ MLAN_OID_11N_CFG_TX_BF_CFG,
+ MLAN_OID_11N_CFG_STREAM_CFG,
+
+ /* 802.11d Configuration Group */
+ MLAN_IOCTL_11D_CFG = 0x000D0000,
+#ifdef STA_SUPPORT
+ MLAN_OID_11D_CFG_ENABLE,
+ MLAN_OID_11D_CLR_CHAN_TABLE,
+#endif /* STA_SUPPORT */
+ MLAN_OID_11D_DOMAIN_INFO,
+
+ /* Register Memory Access Group */
+ MLAN_IOCTL_REG_MEM = 0x000E0000,
+ MLAN_OID_REG_RW,
+ MLAN_OID_EEPROM_RD,
+ MLAN_OID_MEM_RW,
+
+ /* Multi-Radio Configuration Group */
+ MLAN_IOCTL_MFR_CFG = 0x00100000,
+
+ /* 802.11h Configuration Group */
+ MLAN_IOCTL_11H_CFG = 0x00110000,
+ MLAN_OID_11H_CHANNEL_CHECK,
+ MLAN_OID_11H_LOCAL_POWER_CONSTRAINT,
+#if defined(DFS_TESTING_SUPPORT)
+ MLAN_OID_11H_DFS_TESTING,
+#endif
+
+ /* Miscellaneous Configuration Group */
+ MLAN_IOCTL_MISC_CFG = 0x00200000,
+ MLAN_OID_MISC_GEN_IE,
+ MLAN_OID_MISC_REGION,
+ MLAN_OID_MISC_WARM_RESET,
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+ MLAN_OID_MISC_SDIO_MPA_CTRL,
+#endif
+ MLAN_OID_MISC_HOST_CMD,
+ MLAN_OID_MISC_SYS_CLOCK,
+ MLAN_OID_MISC_SOFT_RESET,
+ MLAN_OID_MISC_WWS,
+ MLAN_OID_MISC_INIT_SHUTDOWN,
+ MLAN_OID_MISC_CUSTOM_IE,
+ MLAN_OID_MISC_TX_DATAPAUSE,
+ MLAN_OID_MISC_IP_ADDR,
+ MLAN_OID_MISC_MAC_CONTROL,
+ MLAN_OID_MISC_MEF_CFG,
+ MLAN_OID_MISC_CFP_CODE,
+ MLAN_OID_MISC_COUNTRY_CODE,
+ MLAN_OID_MISC_THERMAL,
+ MLAN_OID_MISC_RX_MGMT_IND,
+ MLAN_OID_MISC_SUBSCRIBE_EVENT,
+#ifdef DEBUG_LEVEL1
+ MLAN_OID_MISC_DRVDBG,
+#endif
+ MLAN_OID_MISC_OTP_USER_DATA,
+};
+
+/** Sub command size */
+#define MLAN_SUB_COMMAND_SIZE 4
+
+/** Enumeration for the action of IOCTL request */
+enum _mlan_act_ioctl
+{
+ MLAN_ACT_SET = 1,
+ MLAN_ACT_GET,
+ MLAN_ACT_CANCEL
+};
+
+/** Enumeration for generic enable/disable */
+enum _mlan_act_generic
+{
+ MLAN_ACT_DISABLE = 0,
+ MLAN_ACT_ENABLE = 1
+};
+
+/** Enumeration for scan mode */
+enum _mlan_scan_mode
+{
+ MLAN_SCAN_MODE_UNCHANGED = 0,
+ MLAN_SCAN_MODE_BSS,
+ MLAN_SCAN_MODE_IBSS,
+ MLAN_SCAN_MODE_ANY
+};
+
+/** Enumeration for scan type */
+enum _mlan_scan_type
+{
+ MLAN_SCAN_TYPE_UNCHANGED = 0,
+ MLAN_SCAN_TYPE_ACTIVE,
+ MLAN_SCAN_TYPE_PASSIVE
+};
+
+/** Max number of supported rates */
+#define MLAN_SUPPORTED_RATES 32
+
+/** RSSI scan */
+#define SCAN_RSSI(RSSI) (0x100 - ((t_u8)(RSSI)))
+
+/** Max passive scan time for each channel in milliseconds */
+#define MRVDRV_MAX_PASSIVE_SCAN_CHAN_TIME 2000
+
+/** Max active scan time for each channel in milliseconds */
+#define MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME 500
+
+/** Maximum number of probes to send on each channel */
+#define MAX_PROBES 4
+
+/** Default number of probes to send on each channel */
+#define DEFAULT_PROBES 4
+
+/**
+ * @brief Sub-structure passed in wlan_ioctl_get_scan_table_entry for each BSS
+ *
+ * Fixed field information returned for the scan response in the IOCTL
+ * response.
+ */
+typedef struct _wlan_get_scan_table_fixed
+{
+ /** BSSID of this network */
+ t_u8 bssid[MLAN_MAC_ADDR_LENGTH];
+ /** Channel this beacon/probe response was detected */
+ t_u8 channel;
+ /** RSSI for the received packet */
+ t_u8 rssi;
+ /** TSF value in microseconds from the firmware at packet reception */
+ t_u64 network_tsf;
+} wlan_get_scan_table_fixed;
+
+/** mlan_802_11_ssid data structure */
+typedef struct _mlan_802_11_ssid
+{
+ /** SSID Length */
+ t_u32 ssid_len;
+ /** SSID information field */
+ t_u8 ssid[MLAN_MAX_SSID_LENGTH];
+} mlan_802_11_ssid, *pmlan_802_11_ssid;
+
+/**
+ * Sructure to retrieve the scan table
+ */
+typedef struct
+{
+ /**
+ * - Zero based scan entry to start retrieval in command request
+ * - Number of scans entries returned in command response
+ */
+ t_u32 scan_number;
+ /**
+ * Buffer marker for multiple wlan_ioctl_get_scan_table_entry structures.
+ * Each struct is padded to the nearest 32 bit boundary.
+ */
+ t_u8 scan_table_entry_buf[1];
+} wlan_ioctl_get_scan_table_info;
+
+/**
+ * Structure passed in the wlan_ioctl_get_scan_table_info for each
+ * BSS returned in the WLAN_GET_SCAN_RESP IOCTL
+ */
+typedef struct _wlan_ioctl_get_scan_table_entry
+{
+ /**
+ * Fixed field length included in the response.
+ *
+ * Length value is included so future fixed fields can be added to the
+ * response without breaking backwards compatibility. Use the length
+ * to find the offset for the bssInfoLength field, not a sizeof() calc.
+ */
+ t_u32 fixed_field_length;
+
+ /**
+ * Length of the BSS Information (probe resp or beacon) that
+ * follows after the fixed_field_length
+ */
+ t_u32 bss_info_length;
+
+ /**
+ * Always present, fixed length data fields for the BSS
+ */
+ wlan_get_scan_table_fixed fixed_fields;
+
+ /*
+ * Probe response or beacon scanned for the BSS.
+ *
+ * Field layout:
+ * - TSF 8 octets
+ * - Beacon Interval 2 octets
+ * - Capability Info 2 octets
+ *
+ * - IEEE Infomation Elements; variable number & length per 802.11 spec
+ */
+ /* t_u8 bss_info_buffer[0]; */
+} wlan_ioctl_get_scan_table_entry;
+
+/** Type definition of mlan_scan_time_params */
+typedef struct _mlan_scan_time_params
+{
+ /** Scan channel time for specific scan in milliseconds */
+ t_u32 specific_scan_time;
+ /** Scan channel time for active scan in milliseconds */
+ t_u32 active_scan_time;
+ /** Scan channel time for passive scan in milliseconds */
+ t_u32 passive_scan_time;
+} mlan_scan_time_params, *pmlan_scan_time_params;
+
+/** Type definition of mlan_user_scan */
+typedef struct _mlan_user_scan
+{
+ /** Length of scan_cfg_buf */
+ t_u32 scan_cfg_len;
+ /** Buffer of scan config */
+ t_u8 scan_cfg_buf[1];
+} mlan_user_scan, *pmlan_user_scan;
+
+/** Type definition of mlan_scan_req */
+typedef struct _mlan_scan_req
+{
+ /** BSS mode for scanning */
+ t_u32 scan_mode;
+ /** Scan type */
+ t_u32 scan_type;
+ /** SSID */
+ mlan_802_11_ssid scan_ssid;
+ /** Scan time parameters */
+ mlan_scan_time_params scan_time;
+ /** Scan config parameters in user scan */
+ mlan_user_scan user_scan;
+} mlan_scan_req, *pmlan_scan_req;
+
+/** Type defnition of mlan_scan_resp */
+typedef struct _mlan_scan_resp
+{
+ /** Number of scan result */
+ t_u32 num_in_scan_table;
+ /** Scan table */
+ t_u8 *pscan_table;
+ /* Age in seconds */
+ t_u32 age_in_secs;
+} mlan_scan_resp, *pmlan_scan_resp;
+
+/** Type definition of mlan_scan_cfg */
+typedef struct _mlan_scan_cfg
+{
+ /** Scan type */
+ t_u32 scan_type;
+ /** BSS mode for scanning */
+ t_u32 scan_mode;
+ /** Scan probe */
+ t_u32 scan_probe;
+ /** Scan time parameters */
+ mlan_scan_time_params scan_time;
+ /** Extended Scan */
+ t_u32 ext_scan;
+} mlan_scan_cfg, *pmlan_scan_cfg;
+
+/** Type defnition of mlan_ds_scan for MLAN_IOCTL_SCAN */
+typedef struct _mlan_ds_scan
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Scan request/response */
+ union
+ {
+ /** Scan request */
+ mlan_scan_req scan_req;
+ /** Scan response */
+ mlan_scan_resp scan_resp;
+ /** Scan config parameters in user scan */
+ mlan_user_scan user_scan;
+ /** Scan config parameters */
+ mlan_scan_cfg scan_cfg;
+ } param;
+} mlan_ds_scan, *pmlan_ds_scan;
+
+/*-----------------------------------------------------------------*/
+/** BSS Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for BSS mode */
+enum _mlan_bss_mode
+{
+ MLAN_BSS_MODE_INFRA = 1,
+ MLAN_BSS_MODE_IBSS,
+ MLAN_BSS_MODE_AUTO
+};
+
+/** Maximum key length */
+#define MLAN_MAX_KEY_LENGTH 32
+
+/** max Wmm AC queues */
+#define MAX_AC_QUEUES 4
+
+/** Maximum atim window in milliseconds */
+#define MLAN_MAX_ATIM_WINDOW 50
+
+/** Minimum beacon interval */
+#define MLAN_MIN_BEACON_INTERVAL 20
+/** Maximum beacon interval */
+#define MLAN_MAX_BEACON_INTERVAL 1000
+/** Default beacon interval */
+#define MLAN_BEACON_INTERVAL 100
+
+/** Receive all packets */
+#define MLAN_PROMISC_MODE 1
+/** Receive multicast packets in multicast list */
+#define MLAN_MULTICAST_MODE 2
+/** Receive all multicast packets */
+#define MLAN_ALL_MULTI_MODE 4
+
+/** Maximum size of multicast list */
+#define MLAN_MAX_MULTICAST_LIST_SIZE 32
+
+/** mlan_multicast_list data structure for MLAN_OID_BSS_MULTICAST_LIST */
+typedef struct _mlan_multicast_list
+{
+ /** Multicast mode */
+ t_u32 mode;
+ /** Number of multicast addresses in the list */
+ t_u32 num_multicast_addr;
+ /** Multicast address list */
+ mlan_802_11_mac_addr mac_list[MLAN_MAX_MULTICAST_LIST_SIZE];
+} mlan_multicast_list, *pmlan_multicast_list;
+
+/** Max channel */
+#define MLAN_MAX_CHANNEL 165
+
+/** Maximum number of channels in table */
+#define MLAN_MAX_CHANNEL_NUM 128
+
+/** Channel/frequence for MLAN_OID_BSS_CHANNEL */
+typedef struct _chan_freq
+{
+ /** Channel Number */
+ t_u32 channel;
+ /** Frequency of this Channel */
+ t_u32 freq;
+} chan_freq;
+
+/** mlan_chan_list data structure for MLAN_OID_BSS_CHANNEL_LIST */
+typedef struct _mlan_chan_list
+{
+ /** Number of channel */
+ t_u32 num_of_chan;
+ /** Channel-Frequency table */
+ chan_freq cf[MLAN_MAX_CHANNEL_NUM];
+} mlan_chan_list;
+
+/** mlan_ssid_bssid data structure for MLAN_OID_BSS_START and MLAN_OID_BSS_FIND_BSS */
+typedef struct _mlan_ssid_bssid
+{
+ /** SSID */
+ mlan_802_11_ssid ssid;
+ /** BSSID */
+ mlan_802_11_mac_addr bssid;
+ /** index in BSSID list, start from 1 */
+ t_u32 idx;
+} mlan_ssid_bssid;
+
+#ifdef UAP_SUPPORT
+/** Maximum packet forward control value */
+#define MAX_PKT_FWD_CTRL 15
+/** Maximum BEACON period */
+#define MAX_BEACON_PERIOD 4000
+/** Minimum BEACON period */
+#define MIN_BEACON_PERIOD 50
+/** Maximum DTIM period */
+#define MAX_DTIM_PERIOD 100
+/** Minimum DTIM period */
+#define MIN_DTIM_PERIOD 1
+/** Maximum TX Power Limit */
+#define MAX_TX_POWER 20
+/** Minimum TX Power Limit */
+#define MIN_TX_POWER 0
+/** MAX station count */
+#define MAX_STA_COUNT 10
+/** Maximum RTS threshold */
+#define MAX_RTS_THRESHOLD 2347
+/** Maximum fragmentation threshold */
+#define MAX_FRAG_THRESHOLD 2346
+/** Minimum fragmentation threshold */
+#define MIN_FRAG_THRESHOLD 256
+/** data rate 54 M */
+#define DATA_RATE_54M 108
+/** antenna A */
+#define ANTENNA_MODE_A 0
+/** antenna B */
+#define ANTENNA_MODE_B 1
+/** transmit antenna */
+#define TX_ANTENNA 1
+/** receive antenna */
+#define RX_ANTENNA 0
+/** Maximum stage out time */
+#define MAX_STAGE_OUT_TIME 864000
+/** Minimum stage out time */
+#define MIN_STAGE_OUT_TIME 300
+/** Maximum Retry Limit */
+#define MAX_RETRY_LIMIT 14
+
+/** Maximum group key timer in seconds */
+#define MAX_GRP_TIMER 86400
+
+/** Maximum value of 4 byte configuration */
+#define MAX_VALID_DWORD 0x7FFFFFFF /* (1 << 31) - 1 */
+
+/** Band config ACS mode */
+#define BAND_CONFIG_ACS_MODE 0x40
+/** Band config manual */
+#define BAND_CONFIG_MANUAL 0x00
+
+/** Maximum data rates */
+#define MAX_DATA_RATES 14
+
+/** auto data rate */
+#define DATA_RATE_AUTO 0
+
+/**filter mode: disable */
+#define MAC_FILTER_MODE_DISABLE 0
+/**filter mode: block mac address */
+#define MAC_FILTER_MODE_ALLOW_MAC 1
+/**filter mode: block mac address */
+#define MAC_FILTER_MODE_BLOCK_MAC 2
+/** Maximum mac filter num */
+#define MAX_MAC_FILTER_NUM 16
+
+/* Bitmap for protocol to use */
+/** No security */
+#define PROTOCOL_NO_SECURITY 0x01
+/** Static WEP */
+#define PROTOCOL_STATIC_WEP 0x02
+/** WPA */
+#define PROTOCOL_WPA 0x08
+/** WPA2 */
+#define PROTOCOL_WPA2 0x20
+/** WP2 Mixed */
+#define PROTOCOL_WPA2_MIXED 0x28
+/** EAP */
+#define PROTOCOL_EAP 0x40
+/** WAPI */
+#define PROTOCOL_WAPI 0x80
+
+/** Key_mgmt_psk */
+#define KEY_MGMT_NONE 0x04
+/** Key_mgmt_none */
+#define KEY_MGMT_PSK 0x02
+/** Key_mgmt_eap */
+#define KEY_MGMT_EAP 0x01
+
+/** TKIP */
+#define CIPHER_TKIP 0x04
+/** AES CCMP */
+#define CIPHER_AES_CCMP 0x08
+
+/** Valid cipher bitmap */
+#define VALID_CIPHER_BITMAP 0x0c
+
+/** Channel List Entry */
+typedef struct _channel_list
+{
+ /** Channel Number */
+ t_u8 chan_number;
+ /** Band Config */
+ t_u8 band_config_type;
+} scan_chan_list;
+
+/** mac_filter data structure */
+typedef struct _mac_filter
+{
+ /** mac filter mode */
+ t_u16 filter_mode;
+ /** mac adress count */
+ t_u16 mac_count;
+ /** mac address list */
+ mlan_802_11_mac_addr mac_list[MAX_MAC_FILTER_NUM];
+} mac_filter;
+
+/** wpa parameter */
+typedef struct _wpa_param
+{
+ /** Pairwise cipher WPA */
+ t_u8 pairwise_cipher_wpa;
+ /** Pairwise cipher WPA2 */
+ t_u8 pairwise_cipher_wpa2;
+ /** group cipher */
+ t_u8 group_cipher;
+ /** RSN replay protection */
+ t_u8 rsn_protection;
+ /** passphrase length */
+ t_u32 length;
+ /** passphrase */
+ t_u8 passphrase[64];
+ /**group key rekey time in seconds */
+ t_u32 gk_rekey_time;
+} wpa_param;
+
+/** wep key */
+typedef struct _wep_key
+{
+ /** key index 0-3 */
+ t_u8 key_index;
+ /** is default */
+ t_u8 is_default;
+ /** length */
+ t_u16 length;
+ /** key data */
+ t_u8 key[26];
+} wep_key;
+
+/** wep param */
+typedef struct _wep_param
+{
+ /** key 0 */
+ wep_key key0;
+ /** key 1 */
+ wep_key key1;
+ /** key 2 */
+ wep_key key2;
+ /** key 3 */
+ wep_key key3;
+} wep_param;
+
+/** Data structure of WMM QoS information */
+typedef struct _wmm_qos_info_t
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ /** QoS UAPSD */
+ t_u8 qos_uapsd:1;
+ /** Reserved */
+ t_u8 reserved:3;
+ /** Parameter set count */
+ t_u8 para_set_count:4;
+#else
+ /** Parameter set count */
+ t_u8 para_set_count:4;
+ /** Reserved */
+ t_u8 reserved:3;
+ /** QoS UAPSD */
+ t_u8 qos_uapsd:1;
+#endif /* BIG_ENDIAN_SUPPORT */
+} wmm_qos_info_t, *pwmm_qos_info_t;
+
+/** Data structure of WMM ECW */
+typedef struct _wmm_ecw_t
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ /** Maximum Ecw */
+ t_u8 ecw_max:4;
+ /** Minimum Ecw */
+ t_u8 ecw_min:4;
+#else
+ /** Minimum Ecw */
+ t_u8 ecw_min:4;
+ /** Maximum Ecw */
+ t_u8 ecw_max:4;
+#endif /* BIG_ENDIAN_SUPPORT */
+} wmm_ecw_t, *pwmm_ecw_t;
+
+/** Data structure of WMM Aci/Aifsn */
+typedef struct _wmm_aci_aifsn_t
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ /** Reserved */
+ t_u8 reserved:1;
+ /** Aci */
+ t_u8 aci:2;
+ /** Acm */
+ t_u8 acm:1;
+ /** Aifsn */
+ t_u8 aifsn:4;
+#else
+ /** Aifsn */
+ t_u8 aifsn:4;
+ /** Acm */
+ t_u8 acm:1;
+ /** Aci */
+ t_u8 aci:2;
+ /** Reserved */
+ t_u8 reserved:1;
+#endif /* BIG_ENDIAN_SUPPORT */
+} wmm_aci_aifsn_t, *pwmm_aci_aifsn_t;
+
+/** Data structure of WMM AC parameters */
+typedef struct _wmm_ac_parameters_t
+{
+ wmm_aci_aifsn_t aci_aifsn; /**< AciAifSn */
+ wmm_ecw_t ecw; /**< Ecw */
+ t_u16 tx_op_limit; /**< Tx op limit */
+} wmm_ac_parameters_t, *pwmm_ac_parameters_t;
+
+/** Data structure of WMM parameter IE */
+typedef struct _wmm_parameter_t
+{
+ /** OuiType: 00:50:f2:02 */
+ t_u8 ouitype[4];
+ /** Oui subtype: 01 */
+ t_u8 ouisubtype;
+ /** version: 01 */
+ t_u8 version;
+ /** QoS information */
+ t_u8 qos_info;
+ /** Reserved */
+ t_u8 reserved;
+ /** AC Parameters Record WMM_AC_BE, WMM_AC_BK, WMM_AC_VI, WMM_AC_VO */
+ wmm_ac_parameters_t ac_params[MAX_AC_QUEUES];
+} wmm_parameter_t, *pwmm_parameter_t;
+
+/** mlan_bss_param
+ * Note: For each entry you must enter an invalid value
+ * in the MOAL function woal_set_sys_config_invalid_data().
+ * Otherwise for a valid data an unwanted TLV will be
+ * added to that command.
+ */
+typedef struct _mlan_uap_bss_param
+{
+ /** AP mac addr */
+ mlan_802_11_mac_addr mac_addr;
+ /** SSID */
+ mlan_802_11_ssid ssid;
+ /** Broadcast ssid control */
+ t_u8 bcast_ssid_ctl;
+ /** Radio control: on/off */
+ t_u8 radio_ctl;
+ /** dtim period */
+ t_u8 dtim_period;
+ /** beacon period */
+ t_u16 beacon_period;
+ /** rates */
+ t_u8 rates[MAX_DATA_RATES];
+ /** Tx data rate */
+ t_u16 tx_data_rate;
+ /** multicast/broadcast data rate */
+ t_u16 mcbc_data_rate;
+ /** Tx power level in dBm */
+ t_u8 tx_power_level;
+ /** Tx antenna */
+ t_u8 tx_antenna;
+ /** Rx antenna */
+ t_u8 rx_antenna;
+ /** packet forward control */
+ t_u8 pkt_forward_ctl;
+ /** max station count */
+ t_u16 max_sta_count;
+ /** mac filter */
+ mac_filter filter;
+ /** station ageout timer in unit of 100ms */
+ t_u32 sta_ageout_timer;
+ /** PS station ageout timer in unit of 100ms */
+ t_u32 ps_sta_ageout_timer;
+ /** RTS threshold */
+ t_u16 rts_threshold;
+ /** fragmentation threshold */
+ t_u16 frag_threshold;
+ /** retry_limit */
+ t_u16 retry_limit;
+ /** pairwise update timeout in milliseconds */
+ t_u32 pairwise_update_timeout;
+ /** pairwise handshake retries */
+ t_u32 pwk_retries;
+ /** groupwise update timeout in milliseconds */
+ t_u32 groupwise_update_timeout;
+ /** groupwise handshake retries */
+ t_u32 gwk_retries;
+ /** preamble type */
+ t_u8 preamble_type;
+ /** band cfg */
+ t_u8 band_cfg;
+ /** channel */
+ t_u8 channel;
+ /** auth mode */
+ t_u16 auth_mode;
+ /** encryption protocol */
+ t_u16 protocol;
+ /** key managment type */
+ t_u16 key_mgmt;
+ /** wep param */
+ wep_param wep_cfg;
+ /** wpa param */
+ wpa_param wpa_cfg;
+ /** Mgmt IE passthru mask */
+ t_u32 mgmt_ie_passthru_mask;
+ /*
+ * 11n HT Cap HTCap_t ht_cap
+ */
+ /** HT Capabilities Info field */
+ t_u16 ht_cap_info;
+ /** A-MPDU Parameters field */
+ t_u8 ampdu_param;
+ /** Supported MCS Set field */
+ t_u8 supported_mcs_set[16];
+ /** HT Extended Capabilities field */
+ t_u16 ht_ext_cap;
+ /** Transmit Beamforming Capabilities field */
+ t_u32 tx_bf_cap;
+ /** Antenna Selection Capability field */
+ t_u8 asel;
+ /** Enable 2040 Coex */
+ t_u8 enable_2040coex;
+ /** key management operation */
+ t_u16 key_mgmt_operation;
+ /** BSS status */
+ t_u16 bss_status;
+#ifdef WIFI_DIRECT_SUPPORT
+ /* pre shared key */
+ t_u8 psk[MLAN_MAX_KEY_LENGTH];
+#endif /* WIFI_DIRECT_SUPPORT */
+ /** Number of channels in scan_channel_list */
+ t_u32 num_of_chan;
+ /** scan channel list in ACS mode */
+ scan_chan_list chan_list[MLAN_MAX_CHANNEL];
+ /** Wmm parameters */
+ wmm_parameter_t wmm_para;
+} mlan_uap_bss_param;
+
+/** mlan_deauth_param */
+typedef struct _mlan_deauth_param
+{
+ /** STA mac addr */
+ t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** deauth reason */
+ t_u16 reason_code;
+} mlan_deauth_param;
+#endif
+
+#ifdef WIFI_DIRECT_SUPPORT
+/** mode: disable wifi direct */
+#define WIFI_DIRECT_MODE_DISABLE 0
+/** mode: listen */
+#define WIFI_DIRECT_MODE_LISTEN 1
+/** mode: GO */
+#define WIFI_DIRECT_MODE_GO 2
+/** mode: client */
+#define WIFI_DIRECT_MODE_CLIENT 3
+/** mode: find */
+#define WIFI_DIRECT_MODE_FIND 4
+/** mode: stop find */
+#define WIFI_DIRECT_MODE_STOP_FIND 5
+#endif
+
+/** Type definition of mlan_ds_bss for MLAN_IOCTL_BSS */
+typedef struct _mlan_ds_bss
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** BSS parameter */
+ union
+ {
+ /** SSID-BSSID for MLAN_OID_BSS_START */
+ mlan_ssid_bssid ssid_bssid;
+ /** BSSID for MLAN_OID_BSS_STOP */
+ mlan_802_11_mac_addr bssid;
+ /** BSS mode for MLAN_OID_BSS_MODE */
+ t_u32 bss_mode;
+ /** BSS channel/frequency for MLAN_OID_BSS_CHANNEL */
+ chan_freq bss_chan;
+ /** BSS channel list for MLAN_OID_BSS_CHANNEL_LIST */
+ mlan_chan_list chanlist;
+ /** MAC address for MLAN_OID_BSS_MAC_ADDR */
+ mlan_802_11_mac_addr mac_addr;
+ /** Multicast list for MLAN_OID_BSS_MULTICAST_LIST */
+ mlan_multicast_list multicast_list;
+ /** Beacon interval for MLAN_OID_IBSS_BCN_INTERVAL */
+ t_u32 bcn_interval;
+ /** ATIM window for MLAN_OID_IBSS_ATIM_WINDOW */
+ t_u32 atim_window;
+#ifdef UAP_SUPPORT
+ /** BSS param for AP mode */
+ mlan_uap_bss_param bss_config;
+ /** deauth param for MLAN_OID_UAP_DEAUTH_STA */
+ mlan_deauth_param deauth_param;
+#endif
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ /** BSS role */
+ t_u8 bss_role;
+#endif
+#ifdef WIFI_DIRECT_SUPPORT
+ t_u16 wfd_mode;
+#endif
+ } param;
+} mlan_ds_bss, *pmlan_ds_bss;
+
+/*-----------------------------------------------------------------*/
+/** Radio Control Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for band */
+enum _mlan_band_def
+{
+ BAND_B = 1,
+ BAND_G = 2,
+ BAND_A = 4,
+ BAND_GN = 8,
+ BAND_AN = 16,
+};
+
+/** NO secondary channel */
+#define NO_SEC_CHANNEL 0
+/** secondary channel is above primary channel */
+#define SEC_CHANNEL_ABOVE 1
+/** secondary channel is below primary channel */
+#define SEC_CHANNEL_BELOW 3
+/** Channel bandwidth */
+#define CHANNEL_BW_20MHZ 0
+#define CHANNEL_BW_40MHZ_ABOVE 1
+#define CHANNEL_BW_40MHZ_BELOW 3
+
+/** Type definition of mlan_ds_band_cfg for MLAN_OID_BAND_CFG */
+typedef struct _mlan_ds_band_cfg
+{
+ /** Infra band */
+ t_u32 config_bands;
+ /** Ad-hoc start band */
+ t_u32 adhoc_start_band;
+ /** Ad-hoc start channel */
+ t_u32 adhoc_channel;
+ /** Ad-hoc channel bandwidth */
+ t_u32 sec_chan_offset;
+ /** fw supported band */
+ t_u32 fw_bands;
+} mlan_ds_band_cfg;
+
+/** Type definition of mlan_ds_ant_cfg for MLAN_OID_ANT_CFG */
+typedef struct _mlan_ds_ant_cfg
+{
+ /** Tx antenna mode */
+ t_u32 tx_antenna;
+ /** Rx antenna mode */
+ t_u32 rx_antenna;
+} mlan_ds_ant_cfg, *pmlan_ds_ant_cfg;
+
+#ifdef WIFI_DIRECT_SUPPORT
+/** Type definition of mlan_ds_remain_chan for MLAN_OID_REMAIN_CHAN_CFG */
+typedef struct _mlan_ds_remain_chan
+{
+ /** remove flag */
+ t_u16 remove;
+ /** status */
+ t_u8 status;
+ /** Band cfg */
+ t_u8 bandcfg;
+ /** channel */
+ t_u8 channel;
+ /** remain time: Unit ms*/
+ t_u32 remain_period;
+} mlan_ds_remain_chan, *pmlan_ds_remain_chan;
+#endif
+
+/** Type definition of mlan_ds_radio_cfg for MLAN_IOCTL_RADIO_CFG */
+typedef struct _mlan_ds_radio_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Radio control parameter */
+ union
+ {
+ /** Radio on/off for MLAN_OID_RADIO_CTRL */
+ t_u32 radio_on_off;
+ /** Band info for MLAN_OID_BAND_CFG */
+ mlan_ds_band_cfg band_cfg;
+ /** Antenna info for MLAN_OID_ANT_CFG */
+ mlan_ds_ant_cfg ant_cfg;
+ /** Antenna info for MLAN_OID_ANT_CFG */
+ t_u32 antenna;
+#ifdef WIFI_DIRECT_SUPPORT
+ /** remain on channel for MLAN_OID_REMAIN_CHAN_CFG */
+ mlan_ds_remain_chan remain_chan;
+#endif
+ } param;
+} mlan_ds_radio_cfg, *pmlan_ds_radio_cfg;
+
+/*-----------------------------------------------------------------*/
+/** SNMP MIB Group */
+/*-----------------------------------------------------------------*/
+/** Type definition of mlan_ds_snmp_mib for MLAN_IOCTL_SNMP_MIB */
+typedef struct _mlan_ds_snmp_mib
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** SNMP MIB parameter */
+ union
+ {
+ /** RTS threshold for MLAN_OID_SNMP_MIB_RTS_THRESHOLD */
+ t_u32 rts_threshold;
+ /** Fragment threshold for MLAN_OID_SNMP_MIB_FRAG_THRESHOLD */
+ t_u32 frag_threshold;
+ /** Retry count for MLAN_OID_SNMP_MIB_RETRY_COUNT */
+ t_u32 retry_count;
+#if defined(UAP_SUPPORT)
+ /** OID value for MLAN_OID_SNMP_MIB_DOT11D/H */
+ t_u32 oid_value;
+#endif
+ /** DTIM period for MLAN_OID_SNMP_MIB_DTIM_PERIOD */
+ t_u32 dtim_period;
+ } param;
+} mlan_ds_snmp_mib, *pmlan_ds_snmp_mib;
+
+/*-----------------------------------------------------------------*/
+/** Status Information Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for ad-hoc status */
+enum _mlan_adhoc_status
+{
+ ADHOC_IDLE,
+ ADHOC_STARTED,
+ ADHOC_JOINED,
+ ADHOC_COALESCED, ADHOC_STARTING
+};
+
+/** Type definition of mlan_ds_get_stats for MLAN_OID_GET_STATS */
+typedef struct _mlan_ds_get_stats
+{
+ /** Statistics counter */
+ /** Multicast transmitted frame count */
+ t_u32 mcast_tx_frame;
+ /** Failure count */
+ t_u32 failed;
+ /** Retry count */
+ t_u32 retry;
+ /** Multi entry count */
+ t_u32 multi_retry;
+ /** Duplicate frame count */
+ t_u32 frame_dup;
+ /** RTS success count */
+ t_u32 rts_success;
+ /** RTS failure count */
+ t_u32 rts_failure;
+ /** Ack failure count */
+ t_u32 ack_failure;
+ /** Rx fragmentation count */
+ t_u32 rx_frag;
+ /** Multicast Tx frame count */
+ t_u32 mcast_rx_frame;
+ /** FCS error count */
+ t_u32 fcs_error;
+ /** Tx frame count */
+ t_u32 tx_frame;
+ /** WEP ICV error count */
+ t_u32 wep_icv_error[4];
+} mlan_ds_get_stats, *pmlan_ds_get_stats;
+
+/** Type definition of mlan_ds_uap_stats for MLAN_OID_GET_STATS */
+typedef struct _mlan_ds_uap_stats
+{
+ /** tkip mic failures */
+ t_u32 tkip_mic_failures;
+ /** ccmp decrypt errors */
+ t_u32 ccmp_decrypt_errors;
+ /** wep undecryptable count */
+ t_u32 wep_undecryptable_count;
+ /** wep icv error count */
+ t_u32 wep_icv_error_count;
+ /** decrypt failure count */
+ t_u32 decrypt_failure_count;
+ /** dot11 multicast tx count */
+ t_u32 mcast_tx_count;
+ /** dot11 failed count */
+ t_u32 failed_count;
+ /** dot11 retry count */
+ t_u32 retry_count;
+ /** dot11 multi retry count */
+ t_u32 multi_retry_count;
+ /** dot11 frame duplicate count */
+ t_u32 frame_dup_count;
+ /** dot11 rts success count */
+ t_u32 rts_success_count;
+ /** dot11 rts failure count */
+ t_u32 rts_failure_count;
+ /** dot11 ack failure count */
+ t_u32 ack_failure_count;
+ /** dot11 rx ragment count */
+ t_u32 rx_fragment_count;
+ /** dot11 mcast rx frame count */
+ t_u32 mcast_rx_frame_count;
+ /** dot11 fcs error count */
+ t_u32 fcs_error_count;
+ /** dot11 tx frame count */
+ t_u32 tx_frame_count;
+ /** dot11 rsna tkip cm invoked */
+ t_u32 rsna_tkip_cm_invoked;
+ /** dot11 rsna 4way handshake failures */
+ t_u32 rsna_4way_hshk_failures;
+} mlan_ds_uap_stats, *pmlan_ds_uap_stats;
+
+/** Mask of last beacon RSSI */
+#define BCN_RSSI_LAST_MASK 0x00000001
+/** Mask of average beacon RSSI */
+#define BCN_RSSI_AVG_MASK 0x00000002
+/** Mask of last data RSSI */
+#define DATA_RSSI_LAST_MASK 0x00000004
+/** Mask of average data RSSI */
+#define DATA_RSSI_AVG_MASK 0x00000008
+/** Mask of last beacon SNR */
+#define BCN_SNR_LAST_MASK 0x00000010
+/** Mask of average beacon SNR */
+#define BCN_SNR_AVG_MASK 0x00000020
+/** Mask of last data SNR */
+#define DATA_SNR_LAST_MASK 0x00000040
+/** Mask of average data SNR */
+#define DATA_SNR_AVG_MASK 0x00000080
+/** Mask of last beacon NF */
+#define BCN_NF_LAST_MASK 0x00000100
+/** Mask of average beacon NF */
+#define BCN_NF_AVG_MASK 0x00000200
+/** Mask of last data NF */
+#define DATA_NF_LAST_MASK 0x00000400
+/** Mask of average data NF */
+#define DATA_NF_AVG_MASK 0x00000800
+/** Mask of all RSSI_INFO */
+#define ALL_RSSI_INFO_MASK 0x00000fff
+
+/** Type definition of mlan_ds_get_signal for MLAN_OID_GET_SIGNAL */
+typedef struct _mlan_ds_get_signal
+{
+ /** Selector of get operation */
+ /*
+ * Bit0: Last Beacon RSSI, Bit1: Average Beacon RSSI,
+ * Bit2: Last Data RSSI, Bit3: Average Data RSSI,
+ * Bit4: Last Beacon SNR, Bit5: Average Beacon SNR,
+ * Bit6: Last Data SNR, Bit7: Average Data SNR,
+ * Bit8: Last Beacon NF, Bit9: Average Beacon NF,
+ * Bit10: Last Data NF, Bit11: Average Data NF
+ */
+ t_u16 selector;
+
+ /** RSSI */
+ /** RSSI of last beacon */
+ t_s16 bcn_rssi_last;
+ /** RSSI of beacon average */
+ t_s16 bcn_rssi_avg;
+ /** RSSI of last data packet */
+ t_s16 data_rssi_last;
+ /** RSSI of data packet average */
+ t_s16 data_rssi_avg;
+
+ /** SNR */
+ /** SNR of last beacon */
+ t_s16 bcn_snr_last;
+ /** SNR of beacon average */
+ t_s16 bcn_snr_avg;
+ /** SNR of last data packet */
+ t_s16 data_snr_last;
+ /** SNR of data packet average */
+ t_s16 data_snr_avg;
+
+ /** NF */
+ /** NF of last beacon */
+ t_s16 bcn_nf_last;
+ /** NF of beacon average */
+ t_s16 bcn_nf_avg;
+ /** NF of last data packet */
+ t_s16 data_nf_last;
+ /** NF of data packet average */
+ t_s16 data_nf_avg;
+} mlan_ds_get_signal, *pmlan_ds_get_signal;
+
+/** mlan_fw_info data structure for MLAN_OID_GET_FW_INFO */
+typedef struct _mlan_fw_info
+{
+ /** Firmware version */
+ t_u32 fw_ver;
+ /** MAC address */
+ mlan_802_11_mac_addr mac_addr;
+ /** Device support for MIMO abstraction of MCSs */
+ t_u8 hw_dev_mcs_support;
+ /** fw supported band */
+ t_u8 fw_bands;
+} mlan_fw_info, *pmlan_fw_info;
+
+/** Version string buffer length */
+#define MLAN_MAX_VER_STR_LEN 128
+
+/** mlan_ver_ext data structure for MLAN_OID_GET_VER_EXT */
+typedef struct _mlan_ver_ext
+{
+ /** Selected version string */
+ t_u32 version_str_sel;
+ /** Version string */
+ char version_str[MLAN_MAX_VER_STR_LEN];
+} mlan_ver_ext, *pmlan_ver_ext;
+
+/** mlan_bss_info data structure for MLAN_OID_GET_BSS_INFO */
+typedef struct _mlan_bss_info
+{
+ /** BSS mode */
+ t_u32 bss_mode;
+ /** SSID */
+ mlan_802_11_ssid ssid;
+ /** Table index */
+ t_u32 scan_table_idx;
+ /** Channel */
+ t_u32 bss_chan;
+ /** Band */
+ t_u8 bss_band;
+ /** Region code */
+ t_u32 region_code;
+ /** Connection status */
+ t_u32 media_connected;
+ /** Radio on */
+ t_u32 radio_on;
+ /** Max power level in dBm */
+ t_u32 max_power_level;
+ /** Min power level in dBm */
+ t_u32 min_power_level;
+ /** Adhoc state */
+ t_u32 adhoc_state;
+ /** NF of last beacon */
+ t_s32 bcn_nf_last;
+ /** wep status */
+ t_u32 wep_status;
+ /** Host Sleep configured flag */
+ t_u32 is_hs_configured;
+ /** Deep Sleep flag */
+ t_u32 is_deep_sleep;
+ /** BSSID */
+ mlan_802_11_mac_addr bssid;
+#ifdef STA_SUPPORT
+ /** Capability Info */
+ t_u16 capability_info;
+ /** Beacon Interval */
+ t_u16 beacon_interval;
+ /** Listen Interval */
+ t_u16 listen_interval;
+ /** Association Id */
+ t_u16 assoc_id;
+ /** AP/Peer supported rates */
+ t_u8 peer_supp_rates[MLAN_SUPPORTED_RATES];
+#endif /* STA_SUPPORT */
+} mlan_bss_info, *pmlan_bss_info;
+
+/** MAXIMUM number of TID */
+#define MAX_NUM_TID 8
+
+/** Max RX Win size */
+#define MAX_RX_WINSIZE 64
+
+/** rx_reorder_tbl */
+typedef struct
+{
+ /** TID */
+ t_u16 tid;
+ /** TA */
+ t_u8 ta[MLAN_MAC_ADDR_LENGTH];
+ /** Start window */
+ t_u32 start_win;
+ /** Window size */
+ t_u32 win_size;
+ /** amsdu flag */
+ t_u8 amsdu;
+ /** buffer status */
+ t_u32 buffer[MAX_RX_WINSIZE];
+} rx_reorder_tbl;
+
+/** tx_ba_stream_tbl */
+typedef struct
+{
+ /** TID */
+ t_u16 tid;
+ /** RA */
+ t_u8 ra[MLAN_MAC_ADDR_LENGTH];
+ /** amsdu flag */
+ t_u8 amsdu;
+} tx_ba_stream_tbl;
+
+/** Debug command number */
+#define DBG_CMD_NUM 5
+
+/** mlan_debug_info data structure for MLAN_OID_GET_DEBUG_INFO */
+typedef struct _mlan_debug_info
+{
+ /* WMM AC_BK count */
+ t_u32 wmm_ac_bk;
+ /* WMM AC_BE count */
+ t_u32 wmm_ac_be;
+ /* WMM AC_VI count */
+ t_u32 wmm_ac_vi;
+ /* WMM AC_VO count */
+ t_u32 wmm_ac_vo;
+ /** Corresponds to max_tx_buf_size member of mlan_adapter*/
+ t_u32 max_tx_buf_size;
+ /** Corresponds to tx_buf_size member of mlan_adapter*/
+ t_u32 tx_buf_size;
+ /** Corresponds to curr_tx_buf_size member of mlan_adapter*/
+ t_u32 curr_tx_buf_size;
+ /** Tx table num */
+ t_u32 tx_tbl_num;
+ /** Tx ba stream table */
+ tx_ba_stream_tbl tx_tbl[MLAN_MAX_TX_BASTREAM_SUPPORTED];
+ /** Rx table num */
+ t_u32 rx_tbl_num;
+ /** Rx reorder table*/
+ rx_reorder_tbl rx_tbl[MLAN_MAX_RX_BASTREAM_SUPPORTED];
+ /** Corresponds to ps_mode member of mlan_adapter */
+ t_u16 ps_mode;
+ /** Corresponds to ps_state member of mlan_adapter */
+ t_u32 ps_state;
+#ifdef STA_SUPPORT
+ /** Corresponds to is_deep_sleep member of mlan_adapter */
+ t_u8 is_deep_sleep;
+#endif /** STA_SUPPORT */
+ /** Corresponds to pm_wakeup_card_req member of mlan_adapter */
+ t_u8 pm_wakeup_card_req;
+ /** Corresponds to pm_wakeup_fw_try member of mlan_adapter */
+ t_u32 pm_wakeup_fw_try;
+ /** Corresponds to is_hs_configured member of mlan_adapter */
+ t_u8 is_hs_configured;
+ /** Corresponds to hs_activated member of mlan_adapter */
+ t_u8 hs_activated;
+ /** Corresponds to pps_uapsd_mode member of mlan_adapter */
+ t_u16 pps_uapsd_mode;
+ /** Corresponds to sleep_period.period member of mlan_adapter */
+ t_u16 sleep_pd;
+ /** Corresponds to wmm_qosinfo member of mlan_private */
+ t_u8 qos_cfg;
+ /** Corresponds to tx_lock_flag member of mlan_adapter */
+ t_u8 tx_lock_flag;
+ /** Corresponds to port_open member of mlan_private */
+ t_u8 port_open;
+ /** Corresponds to scan_processing member of mlan_adapter */
+ t_u32 scan_processing;
+ /** Number of host to card command failures */
+ t_u32 num_cmd_host_to_card_failure;
+ /** Number of host to card sleep confirm failures */
+ t_u32 num_cmd_sleep_cfm_host_to_card_failure;
+ /** Number of host to card Tx failures */
+ t_u32 num_tx_host_to_card_failure;
+ /** Number of card to host command/event failures */
+ t_u32 num_cmdevt_card_to_host_failure;
+ /** Number of card to host Rx failures */
+ t_u32 num_rx_card_to_host_failure;
+ /** Number of interrupt read failures */
+ t_u32 num_int_read_failure;
+ /** Last interrupt status */
+ t_u32 last_int_status;
+ /** Number of deauthentication events */
+ t_u32 num_event_deauth;
+ /** Number of disassosiation events */
+ t_u32 num_event_disassoc;
+ /** Number of link lost events */
+ t_u32 num_event_link_lost;
+ /** Number of deauthentication commands */
+ t_u32 num_cmd_deauth;
+ /** Number of association comamnd successes */
+ t_u32 num_cmd_assoc_success;
+ /** Number of association command failures */
+ t_u32 num_cmd_assoc_failure;
+ /** Number of Tx timeouts */
+ t_u32 num_tx_timeout;
+ /** Number of command timeouts */
+ t_u32 num_cmd_timeout;
+ /** Timeout command ID */
+ t_u16 timeout_cmd_id;
+ /** Timeout command action */
+ t_u16 timeout_cmd_act;
+ /** List of last command IDs */
+ t_u16 last_cmd_id[DBG_CMD_NUM];
+ /** List of last command actions */
+ t_u16 last_cmd_act[DBG_CMD_NUM];
+ /** Last command index */
+ t_u16 last_cmd_index;
+ /** List of last command response IDs */
+ t_u16 last_cmd_resp_id[DBG_CMD_NUM];
+ /** Last command response index */
+ t_u16 last_cmd_resp_index;
+ /** List of last events */
+ t_u16 last_event[DBG_CMD_NUM];
+ /** Last event index */
+ t_u16 last_event_index;
+
+ /** Corresponds to data_sent member of mlan_adapter */
+ t_u8 data_sent;
+ /** Corresponds to cmd_sent member of mlan_adapter */
+ t_u8 cmd_sent;
+ /** SDIO multiple port read bitmap */
+ t_u32 mp_rd_bitmap;
+ /** SDIO multiple port write bitmap */
+ t_u32 mp_wr_bitmap;
+ /** Current available port for read */
+ t_u8 curr_rd_port;
+ /** Current available port for write */
+ t_u8 curr_wr_port;
+ /** Corresponds to cmdresp_received member of mlan_adapter */
+ t_u8 cmd_resp_received;
+ /** Corresponds to event_received member of mlan_adapter */
+ t_u8 event_received;
+ /** pendig tx pkts */
+ t_u32 tx_pkts_queued;
+#ifdef UAP_SUPPORT
+ /** pending bridge pkts */
+ t_u16 num_bridge_pkts;
+ /** dropped pkts */
+ t_u32 num_drop_pkts;
+#endif
+} mlan_debug_info, *pmlan_debug_info;
+
+#ifdef UAP_SUPPORT
+/** Maximum number of clients supported by AP */
+#define MAX_NUM_CLIENTS MAX_STA_COUNT
+
+/** station info */
+typedef struct _sta_info
+{
+ /** STA MAC address */
+ t_u8 mac_address[MLAN_MAC_ADDR_LENGTH];
+ /** Power mfg status */
+ t_u8 power_mfg_status;
+ /** RSSI */
+ t_s8 rssi;
+} sta_info;
+
+/** mlan_ds_sta_list structure for MLAN_OID_UAP_STA_LIST */
+typedef struct _mlan_ds_sta_list
+{
+ /** station count */
+ t_u16 sta_count;
+ /** station list */
+ sta_info info[MAX_NUM_CLIENTS];
+} mlan_ds_sta_list, *pmlan_ds_sta_list;
+#endif
+
+/** Type definition of mlan_ds_get_info for MLAN_IOCTL_GET_INFO */
+typedef struct _mlan_ds_get_info
+{
+ /** Sub-command */
+ t_u32 sub_command;
+
+ /** Status information parameter */
+ union
+ {
+ /** Signal information for MLAN_OID_GET_SIGNAL */
+ mlan_ds_get_signal signal;
+ /** Statistics information for MLAN_OID_GET_STATS */
+ mlan_ds_get_stats stats;
+ /** Firmware information for MLAN_OID_GET_FW_INFO */
+ mlan_fw_info fw_info;
+ /** Extended version information for MLAN_OID_GET_VER_EXT */
+ mlan_ver_ext ver_ext;
+ /** BSS information for MLAN_OID_GET_BSS_INFO */
+ mlan_bss_info bss_info;
+ /** Debug information for MLAN_OID_GET_DEBUG_INFO */
+ mlan_debug_info debug_info;
+#ifdef UAP_SUPPORT
+ /** UAP Statistics information for MLAN_OID_GET_STATS */
+ mlan_ds_uap_stats ustats;
+ /** UAP station list for MLAN_OID_UAP_STA_LIST */
+ mlan_ds_sta_list sta_list;
+#endif
+ } param;
+} mlan_ds_get_info, *pmlan_ds_get_info;
+
+/*-----------------------------------------------------------------*/
+/** Security Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for authentication mode */
+enum _mlan_auth_mode
+{
+ MLAN_AUTH_MODE_OPEN = 0x00,
+ MLAN_AUTH_MODE_SHARED = 0x01,
+ MLAN_AUTH_MODE_NETWORKEAP = 0x80,
+ MLAN_AUTH_MODE_AUTO = 0xFF,
+};
+
+/** Enumeration for encryption mode */
+enum _mlan_encryption_mode
+{
+ MLAN_ENCRYPTION_MODE_NONE = 0,
+ MLAN_ENCRYPTION_MODE_WEP40 = 1,
+ MLAN_ENCRYPTION_MODE_TKIP = 2,
+ MLAN_ENCRYPTION_MODE_CCMP = 3,
+ MLAN_ENCRYPTION_MODE_WEP104 = 4,
+};
+
+/** Enumeration for PSK */
+enum _mlan_psk_type
+{
+ MLAN_PSK_PASSPHRASE = 1,
+ MLAN_PSK_PMK,
+ MLAN_PSK_CLEAR,
+ MLAN_PSK_QUERY,
+};
+
+/** The bit to indicate the key is for unicast */
+#define MLAN_KEY_INDEX_UNICAST 0x40000000
+/** The key index to indicate default key */
+#define MLAN_KEY_INDEX_DEFAULT 0x000000ff
+/** Maximum key length */
+// #define MLAN_MAX_KEY_LENGTH 32
+/** Minimum passphrase length */
+#define MLAN_MIN_PASSPHRASE_LENGTH 8
+/** Maximum passphrase length */
+#define MLAN_MAX_PASSPHRASE_LENGTH 63
+/** PMK length */
+#define MLAN_PMK_HEXSTR_LENGTH 64
+/* A few details needed for WEP (Wireless Equivalent Privacy) */
+/** 104 bits */
+#define MAX_WEP_KEY_SIZE 13
+/** 40 bits RC4 - WEP */
+#define MIN_WEP_KEY_SIZE 5
+/** packet number size */
+#define PN_SIZE 16
+/** max seq size of wpa/wpa2 key */
+#define SEQ_MAX_SIZE 8
+
+/** key flag for tx_seq */
+#define KEY_FLAG_TX_SEQ_VALID 0x00000001
+/** key flag for rx_seq */
+#define KEY_FLAG_RX_SEQ_VALID 0x00000002
+/** key flag for group key */
+#define KEY_FLAG_GROUP_KEY 0x00000004
+/** key flag for tx and rx */
+#define KEY_FLAG_SET_TX_KEY 0x00000008
+/** key flag for remove key */
+#define KEY_FLAG_REMOVE_KEY 0x80000000
+
+/** Type definition of mlan_ds_encrypt_key for MLAN_OID_SEC_CFG_ENCRYPT_KEY */
+typedef struct _mlan_ds_encrypt_key
+{
+ /** Key disabled, all other fields will be ignore when this flag set to MTRUE */
+ t_u32 key_disable;
+ /** key removed flag, when this flag is set to MTRUE, only key_index will be check */
+ t_u32 key_remove;
+ /** Key index, used as current tx key index when is_current_wep_key is set to MTRUE */
+ t_u32 key_index;
+ /** Current Tx key flag */
+ t_u32 is_current_wep_key;
+ /** Key length */
+ t_u32 key_len;
+ /** Key */
+ t_u8 key_material[MLAN_MAX_KEY_LENGTH];
+ /** mac address */
+ t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** wapi key flag */
+ t_u32 is_wapi_key;
+ /** Initial packet number */
+ t_u8 pn[PN_SIZE];
+ /** key flags */
+ t_u32 key_flags;
+} mlan_ds_encrypt_key, *pmlan_ds_encrypt_key;
+
+/** Type definition of mlan_passphrase_t */
+typedef struct _mlan_passphrase_t
+{
+ /** Length of passphrase */
+ t_u32 passphrase_len;
+ /** Passphrase */
+ t_u8 passphrase[MLAN_MAX_PASSPHRASE_LENGTH];
+} mlan_passphrase_t;
+
+/** Type defnition of mlan_pmk_t */
+typedef struct _mlan_pmk_t
+{
+ /** PMK */
+ t_u8 pmk[MLAN_MAX_KEY_LENGTH];
+} mlan_pmk_t;
+
+/** Embedded supplicant RSN type: No RSN */
+#define RSN_TYPE_NO_RSN MBIT(0)
+/** Embedded supplicant RSN type: WPA */
+#define RSN_TYPE_WPA MBIT(3)
+/** Embedded supplicant RSN type: WPA-NONE */
+#define RSN_TYPE_WPANONE MBIT(4)
+/** Embedded supplicant RSN type: WPA2 */
+#define RSN_TYPE_WPA2 MBIT(5)
+/** Embedded supplicant RSN type: RFU */
+#define RSN_TYPE_VALID_BITS (RSN_TYPE_NO_RSN | RSN_TYPE_WPA | RSN_TYPE_WPANONE | RSN_TYPE_WPA2)
+
+/** Embedded supplicant cipher type: TKIP */
+#define EMBED_CIPHER_TKIP MBIT(2)
+/** Embedded supplicant cipher type: AES */
+#define EMBED_CIPHER_AES MBIT(3)
+/** Embedded supplicant cipher type: RFU */
+#define EMBED_CIPHER_VALID_BITS (EMBED_CIPHER_TKIP | EMBED_CIPHER_AES)
+
+/** Type definition of mlan_ds_passphrase for MLAN_OID_SEC_CFG_PASSPHRASE */
+typedef struct _mlan_ds_passphrase
+{
+ /** SSID may be used */
+ mlan_802_11_ssid ssid;
+ /** BSSID may be used */
+ mlan_802_11_mac_addr bssid;
+ /** Flag for passphrase or pmk used */
+ t_u16 psk_type;
+ /** Passphrase or PMK */
+ union
+ {
+ /** Passphrase */
+ mlan_passphrase_t passphrase;
+ /** PMK */
+ mlan_pmk_t pmk;
+ } psk;
+} mlan_ds_passphrase, *pmlan_ds_passphrase;
+
+/** Type definition of mlan_ds_esupp_mode for MLAN_OID_SEC_CFG_ESUPP_MODE */
+typedef struct _mlan_ds_ewpa_mode
+{
+ /** RSN mode */
+ t_u32 rsn_mode;
+ /** Active pairwise cipher */
+ t_u32 act_paircipher;
+ /** Active pairwise cipher */
+ t_u32 act_groupcipher;
+} mlan_ds_esupp_mode, *pmlan_ds_esupp_mode;
+
+/** Type definition of mlan_ds_sec_cfg for MLAN_IOCTL_SEC_CFG */
+typedef struct _mlan_ds_sec_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Security configuration parameter */
+ union
+ {
+ /** Authentication mode for MLAN_OID_SEC_CFG_AUTH_MODE */
+ t_u32 auth_mode;
+ /** Encryption mode for MLAN_OID_SEC_CFG_ENCRYPT_MODE */
+ t_u32 encrypt_mode;
+ /** WPA enabled flag for MLAN_OID_SEC_CFG_WPA_ENABLED */
+ t_u32 wpa_enabled;
+ /** WAPI enabled flag for MLAN_OID_SEC_CFG_WAPI_ENABLED */
+ t_u32 wapi_enabled;
+ /** Port Control enabled flag for MLAN_OID_SEC_CFG_PORT_CTRL */
+ t_u32 port_ctrl_enabled;
+ /** Encryption key for MLAN_OID_SEC_CFG_ENCRYPT_KEY */
+ mlan_ds_encrypt_key encrypt_key;
+ /** Passphrase for MLAN_OID_SEC_CFG_PASSPHRASE */
+ mlan_ds_passphrase passphrase;
+ /** Embedded supplicant WPA enabled flag for MLAN_OID_SEC_CFG_EWPA_ENABLED */
+ t_u32 ewpa_enabled;
+ /** Embedded supplicant mode for MLAN_OID_SEC_CFG_ESUPP_MODE */
+ mlan_ds_esupp_mode esupp_mode;
+ } param;
+} mlan_ds_sec_cfg, *pmlan_ds_sec_cfg;
+
+/*-----------------------------------------------------------------*/
+/** Rate Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for rate type */
+enum _mlan_rate_type
+{
+ MLAN_RATE_INDEX,
+ MLAN_RATE_VALUE
+};
+
+/** Enumeration for rate format */
+enum _mlan_rate_format
+{
+ MLAN_RATE_FORMAT_LG = 0,
+ MLAN_RATE_FORMAT_HT,
+ MLAN_RATE_FORMAT_AUTO = 0xFF,
+};
+/** Max bitmap rates size */
+#define MAX_BITMAP_RATES_SIZE 10
+
+/** Type definition of mlan_rate_cfg_t for MLAN_OID_RATE_CFG */
+typedef struct _mlan_rate_cfg_t
+{
+ /** Fixed rate: 0, auto rate: 1 */
+ t_u32 is_rate_auto;
+ /** Rate type. 0: index; 1: valude */
+ t_u32 rate_type;
+ /** Rate/MCS index or rate value if fixed rate */
+ t_u32 rate;
+ /** Rate Bitmap */
+ t_u16 bitmap_rates[MAX_BITMAP_RATES_SIZE];
+} mlan_rate_cfg_t;
+
+/** HT channel bandwidth */
+typedef enum _mlan_ht_bw
+{
+ MLAN_HT_BW20,
+ MLAN_HT_BW40,
+} mlan_ht_bw;
+
+/** HT guard interval */
+typedef enum _mlan_ht_gi
+{
+ MLAN_HT_LGI,
+ MLAN_HT_SGI,
+} mlan_ht_gi;
+
+/** Band and BSS mode */
+typedef struct _mlan_band_data_rate
+{
+ /** Band configuration */
+ t_u8 config_bands;
+ /** BSS mode (Infra or IBSS) */
+ t_u8 bss_mode;
+} mlan_band_data_rate;
+
+/** Type definition of mlan_data_rate for MLAN_OID_GET_DATA_RATE */
+typedef struct _mlan_data_rate
+{
+ /** Tx data rate */
+ t_u32 tx_data_rate;
+ /** Rx data rate */
+ t_u32 rx_data_rate;
+
+ /** Tx channel bandwidth */
+ t_u32 tx_ht_bw;
+ /** Tx guard interval */
+ t_u32 tx_ht_gi;
+ /** Rx channel bandwidth */
+ t_u32 rx_ht_bw;
+ /** Rx guard interval */
+ t_u32 rx_ht_gi;
+} mlan_data_rate;
+
+/** Type definition of mlan_ds_rate for MLAN_IOCTL_RATE */
+typedef struct _mlan_ds_rate
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Rate configuration parameter */
+ union
+ {
+ /** Rate configuration for MLAN_OID_RATE_CFG */
+ mlan_rate_cfg_t rate_cfg;
+ /** Data rate for MLAN_OID_GET_DATA_RATE */
+ mlan_data_rate data_rate;
+ /** Supported rates for MLAN_OID_SUPPORTED_RATES */
+ t_u8 rates[MLAN_SUPPORTED_RATES];
+ /** Band/BSS mode for getting supported rates */
+ mlan_band_data_rate rate_band_cfg;
+ } param;
+} mlan_ds_rate, *pmlan_ds_rate;
+
+/*-----------------------------------------------------------------*/
+/** Power Configuration Group */
+/*-----------------------------------------------------------------*/
+
+/** Type definition of mlan_power_cfg_t for MLAN_OID_POWER_CFG */
+typedef struct _mlan_power_cfg_t
+{
+ /** Is power auto */
+ t_u32 is_power_auto;
+ /** Power level in dBm */
+ t_u32 power_level;
+} mlan_power_cfg_t;
+
+/** max power table size */
+#define MAX_POWER_TABLE_SIZE 128
+
+/** The HT BW40 bit in Tx rate index */
+#define TX_RATE_HT_BW40_BIT MBIT(7)
+
+/** Type definition of mlan_power_cfg_ext for MLAN_OID_POWER_CFG_EXT */
+typedef struct _mlan_power_cfg_ext
+{
+ /** Length of power_data */
+ t_u32 len;
+ /** Buffer of power configuration data */
+ t_u32 power_data[MAX_POWER_TABLE_SIZE];
+} mlan_power_cfg_ext;
+
+/** Type definition of mlan_ds_power_cfg for MLAN_IOCTL_POWER_CFG */
+typedef struct _mlan_ds_power_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Power configuration parameter */
+ union
+ {
+ /** Power configuration for MLAN_OID_POWER_CFG */
+ mlan_power_cfg_t power_cfg;
+ /** Extended power configuration for MLAN_OID_POWER_CFG_EXT */
+ mlan_power_cfg_ext power_ext;
+ } param;
+} mlan_ds_power_cfg, *pmlan_ds_power_cfg;
+
+/*-----------------------------------------------------------------*/
+/** Power Management Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Host sleep config conditions : Cancel */
+#define HOST_SLEEP_CFG_CANCEL 0xffffffff
+
+/** Host sleep config condition: broadcast data */
+#define HOST_SLEEP_COND_BROADCAST_DATA MBIT(0)
+/** Host sleep config condition: unicast data */
+#define HOST_SLEEP_COND_UNICAST_DATA MBIT(1)
+/** Host sleep config condition: mac event */
+#define HOST_SLEEP_COND_MAC_EVENT MBIT(2)
+/** Host sleep config condition: multicast data */
+#define HOST_SLEEP_COND_MULTICAST_DATA MBIT(3)
+
+/** Host sleep config conditions: Default */
+#define HOST_SLEEP_DEF_COND (HOST_SLEEP_COND_BROADCAST_DATA | HOST_SLEEP_COND_UNICAST_DATA | HOST_SLEEP_COND_MAC_EVENT)
+/** Host sleep config GPIO : Default */
+#define HOST_SLEEP_DEF_GPIO 0xff
+/** Host sleep config gap : Default */
+#define HOST_SLEEP_DEF_GAP 200
+
+/** Type definition of mlan_ds_hs_cfg for MLAN_OID_PM_CFG_HS_CFG */
+typedef struct _mlan_ds_hs_cfg
+{
+ /** MTRUE to invoke the HostCmd, MFALSE otherwise */
+ t_u32 is_invoke_hostcmd;
+ /** Host sleep config condition */
+ /** Bit0: broadcast data
+ * Bit1: unicast data
+ * Bit2: mac event
+ * Bit3: multicast data
+ */
+ t_u32 conditions;
+ /** GPIO pin or 0xff for interface */
+ t_u32 gpio;
+ /** Gap in milliseconds or or 0xff for special setting when GPIO is used to wakeup host */
+ t_u32 gap;
+} mlan_ds_hs_cfg, *pmlan_ds_hs_cfg;
+
+/** Enable deep sleep mode */
+#define DEEP_SLEEP_ON 1
+/** Disable deep sleep mode */
+#define DEEP_SLEEP_OFF 0
+
+/** Default idle time in milliseconds for auto deep sleep */
+#define DEEP_SLEEP_IDLE_TIME 100
+
+typedef struct _mlan_ds_auto_ds
+{
+ /** auto ds mode, 0 - disable, 1 - enable */
+ t_u16 auto_ds;
+ /** auto ds idle time in milliseconds */
+ t_u16 idletime;
+} mlan_ds_auto_ds;
+
+/** Type definition of mlan_ds_inactivity_to for MLAN_OID_PM_CFG_INACTIVITY_TO */
+typedef struct _mlan_ds_inactivity_to
+{
+ /** Timeout unit in microsecond, 0 means 1000us (1ms) */
+ t_u32 timeout_unit;
+ /** Inactivity timeout for unicast data */
+ t_u32 unicast_timeout;
+ /** Inactivity timeout for multicast data */
+ t_u32 mcast_timeout;
+ /** Timeout for additional Rx traffic after Null PM1 packet exchange */
+ t_u32 ps_entry_timeout;
+} mlan_ds_inactivity_to, *pmlan_ds_inactivity_to;
+
+/** Minimum sleep period in milliseconds */
+#define MIN_SLEEP_PERIOD 10
+/** Maximum sleep period in milliseconds */
+#define MAX_SLEEP_PERIOD 60
+/** Special setting for UPSD certification tests */
+#define SLEEP_PERIOD_RESERVED_FF 0xFF
+
+/** PS null interval disable */
+#define PS_NULL_DISABLE (-1)
+
+/** Local listen interval disable */
+#define MRVDRV_LISTEN_INTERVAL_DISABLE (-1)
+/** Minimum listen interval */
+#define MRVDRV_MIN_LISTEN_INTERVAL 0
+
+/** Minimum multiple DTIM */
+#define MRVDRV_MIN_MULTIPLE_DTIM 0
+/** Maximum multiple DTIM */
+#define MRVDRV_MAX_MULTIPLE_DTIM 5
+/** Ignore multiple DTIM */
+#define MRVDRV_IGNORE_MULTIPLE_DTIM 0xfffe
+/** Match listen interval to closest DTIM */
+#define MRVDRV_MATCH_CLOSEST_DTIM 0xfffd
+
+/** Minimum adhoc awake period */
+#define MIN_ADHOC_AWAKE_PD 0
+/** Maximum adhoc awake period */
+#define MAX_ADHOC_AWAKE_PD 31
+/** Special adhoc awake period */
+#define SPECIAL_ADHOC_AWAKE_PD 255
+
+/** Minimum beacon miss timeout in milliseconds */
+#define MIN_BCN_MISS_TO 0
+/** Maximum beacon miss timeout in milliseconds */
+#define MAX_BCN_MISS_TO 50
+/** Disable beacon miss timeout */
+#define DISABLE_BCN_MISS_TO 65535
+
+/** Minimum delay to PS in milliseconds */
+#define MIN_DELAY_TO_PS 0
+/** Maximum delay to PS in milliseconds */
+#define MAX_DELAY_TO_PS 65535
+/** Delay to PS unchanged */
+#define DELAY_TO_PS_UNCHANGED (-1)
+/** Default delay to PS in milliseconds */
+#define DELAY_TO_PS_DEFAULT 1000
+
+/** PS mode: Unchanged */
+#define PS_MODE_UNCHANGED 0
+/** PS mode: Auto */
+#define PS_MODE_AUTO 1
+/** PS mode: Poll */
+#define PS_MODE_POLL 2
+/** PS mode: Null */
+#define PS_MODE_NULL 3
+
+/** Type definition of mlan_ds_ps_cfg for MLAN_OID_PM_CFG_PS_CFG */
+typedef struct _mlan_ds_ps_cfg
+{
+ /** PS null interval in seconds */
+ t_u32 ps_null_interval;
+ /** Multiple DTIM interval */
+ t_u32 multiple_dtim_interval;
+ /** Listen interval */
+ t_u32 listen_interval;
+ /** Adhoc awake period */
+ t_u32 adhoc_awake_period;
+ /** Beacon miss timeout in milliseconds */
+ t_u32 bcn_miss_timeout;
+ /** Delay to PS in milliseconds */
+ t_s32 delay_to_ps;
+ /** PS mode */
+ t_u32 ps_mode;
+} mlan_ds_ps_cfg, *pmlan_ds_ps_cfg;
+
+/** Type definition of mlan_ds_sleep_params for MLAN_OID_PM_CFG_SLEEP_PARAMS */
+typedef struct _mlan_ds_sleep_params
+{
+ /** Error */
+ t_u32 error;
+ /** Offset in microseconds */
+ t_u32 offset;
+ /** Stable time in microseconds */
+ t_u32 stable_time;
+ /** Calibration control */
+ t_u32 cal_control;
+ /** External sleep clock */
+ t_u32 ext_sleep_clk;
+ /** Reserved */
+ t_u32 reserved;
+} mlan_ds_sleep_params, *pmlan_ds_sleep_params;
+
+/** sleep_param */
+typedef struct _ps_sleep_param
+{
+ /** control bitmap */
+ t_u32 ctrl_bitmap;
+ /** minimum sleep period (micro second) */
+ t_u32 min_sleep;
+ /** maximum sleep period (micro second) */
+ t_u32 max_sleep;
+} ps_sleep_param;
+
+/** inactivity sleep_param */
+typedef struct _inact_sleep_param
+{
+ /** inactivity timeout (micro second) */
+ t_u32 inactivity_to;
+ /** miniumu awake period (micro second) */
+ t_u32 min_awake;
+ /** maximum awake period (micro second) */
+ t_u32 max_awake;
+} inact_sleep_param;
+
+/** flag for ps mode */
+#define PS_FLAG_PS_MODE 1
+/** flag for sleep param */
+#define PS_FLAG_SLEEP_PARAM 2
+/** flag for inactivity sleep param */
+#define PS_FLAG_INACT_SLEEP_PARAM 4
+
+/** Disable power mode */
+#define PS_MODE_DISABLE 0
+/** Enable periodic dtim ps */
+#define PS_MODE_PERIODIC_DTIM 1
+/** Enable inactivity ps */
+#define PS_MODE_INACTIVITY 2
+
+/** mlan_ds_ps_mgmt */
+typedef struct _mlan_ds_ps_mgmt
+{
+ /** flags for valid field */
+ t_u16 flags;
+ /** power mode */
+ t_u16 ps_mode;
+ /** sleep param */
+ ps_sleep_param sleep_param;
+ /** inactivity sleep param */
+ inact_sleep_param inact_param;
+} mlan_ds_ps_mgmt;
+
+/** mlan_ds_ps_info */
+typedef struct _mlan_ds_ps_info
+{
+ /** suspend allowed flag */
+ t_u32 is_suspend_allowed;
+} mlan_ds_ps_info;
+
+/** Type definition of mlan_ds_pm_cfg for MLAN_IOCTL_PM_CFG */
+typedef struct _mlan_ds_pm_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Power management parameter */
+ union
+ {
+ /** Power saving mode for MLAN_OID_PM_CFG_IEEE_PS */
+ t_u32 ps_mode;
+ /** Host Sleep configuration for MLAN_OID_PM_CFG_HS_CFG */
+ mlan_ds_hs_cfg hs_cfg;
+ /** Deep sleep mode for MLAN_OID_PM_CFG_DEEP_SLEEP */
+ mlan_ds_auto_ds auto_deep_sleep;
+ /** Inactivity timeout for MLAN_OID_PM_CFG_INACTIVITY_TO */
+ mlan_ds_inactivity_to inactivity_to;
+ /** Sleep period for MLAN_OID_PM_CFG_SLEEP_PD */
+ t_u32 sleep_period;
+ /** PS configuration parameters for MLAN_OID_PM_CFG_PS_CFG */
+ mlan_ds_ps_cfg ps_cfg;
+ /** PS configuration parameters for MLAN_OID_PM_CFG_SLEEP_PARAMS */
+ mlan_ds_sleep_params sleep_params;
+ /** PS configuration parameters for MLAN_OID_PM_CFG_PS_MODE */
+ mlan_ds_ps_mgmt ps_mgmt;
+ /** power info for MLAN_OID_PM_INFO */
+ mlan_ds_ps_info ps_info;
+ } param;
+} mlan_ds_pm_cfg, *pmlan_ds_pm_cfg;
+
+/*-----------------------------------------------------------------*/
+/** WMM Configuration Group */
+/*-----------------------------------------------------------------*/
+
+/** WMM TSpec size */
+#define MLAN_WMM_TSPEC_SIZE 63
+/** WMM Add TS extra IE bytes */
+#define MLAN_WMM_ADDTS_EXTRA_IE_BYTES 256
+/** WMM statistics for packets hist bins */
+#define MLAN_WMM_STATS_PKTS_HIST_BINS 7
+/** Maximum number of AC QOS queues available */
+#define MLAN_WMM_MAX_AC_QUEUES 4
+
+/**
+ * @brief IOCTL structure to send an ADDTS request and retrieve the response.
+ *
+ * IOCTL structure from the application layer relayed to firmware to
+ * instigate an ADDTS management frame with an appropriate TSPEC IE as well
+ * as any additional IEs appended in the ADDTS Action frame.
+ *
+ * @sa woal_wmm_addts_req_ioctl
+ */
+typedef struct
+{
+ mlan_cmd_result_e cmd_result; /**< Firmware execution result */
+
+ t_u32 timeout_ms; /**< Timeout value in milliseconds */
+ t_u8 ieee_status_code; /**< IEEE status code */
+
+ t_u32 ie_data_len; /**< Length of ie block in ie_data */
+ t_u8 ie_data[MLAN_WMM_TSPEC_SIZE /**< TSPEC to send in the ADDTS */
+ + MLAN_WMM_ADDTS_EXTRA_IE_BYTES]; /**< Extra IE buf*/
+} wlan_ioctl_wmm_addts_req_t;
+
+/**
+ * @brief IOCTL structure to send a DELTS request.
+ *
+ * IOCTL structure from the application layer relayed to firmware to
+ * instigate an DELTS management frame with an appropriate TSPEC IE.
+ *
+ * @sa woal_wmm_delts_req_ioctl
+ */
+typedef struct
+{
+ mlan_cmd_result_e cmd_result; /**< Firmware execution result */
+ t_u8 ieee_reason_code; /**< IEEE reason code sent, unused for WMM */
+ t_u32 ie_data_len; /**< Length of ie block in ie_data */
+ t_u8 ie_data[MLAN_WMM_TSPEC_SIZE]; /**< TSPEC to send in the DELTS */
+} wlan_ioctl_wmm_delts_req_t;
+
+/**
+ * @brief IOCTL structure to configure a specific AC Queue's parameters
+ *
+ * IOCTL structure from the application layer relayed to firmware to
+ * get, set, or default the WMM AC queue parameters.
+ *
+ * - msdu_lifetime_expiry is ignored if set to 0 on a set command
+ *
+ * @sa woal_wmm_queue_config_ioctl
+ */
+typedef struct
+{
+ mlan_wmm_queue_config_action_e action; /**< Set, Get, or Default */
+ mlan_wmm_ac_e access_category; /**< WMM_AC_BK(0) to WMM_AC_VO(3) */
+ t_u16 msdu_lifetime_expiry; /**< lifetime expiry in TUs */
+ t_u8 supported_rates[10]; /**< Not supported yet */
+} wlan_ioctl_wmm_queue_config_t;
+
+/**
+ * @brief IOCTL structure to start, stop, and get statistics for a WMM AC
+ *
+ * IOCTL structure from the application layer relayed to firmware to
+ * start or stop statistical collection for a given AC. Also used to
+ * retrieve and clear the collected stats on a given AC.
+ *
+ * @sa woal_wmm_queue_stats_ioctl
+ */
+typedef struct
+{
+ /** Action of Queue Config : Start, Stop, or Get */
+ mlan_wmm_queue_stats_action_e action;
+ /** User Priority */
+ t_u8 user_priority;
+ /** Number of successful packets transmitted */
+ t_u16 pkt_count;
+ /** Packets lost; not included in pkt_count */
+ t_u16 pkt_loss;
+ /** Average Queue delay in microseconds */
+ t_u32 avg_queue_delay;
+ /** Average Transmission delay in microseconds */
+ t_u32 avg_tx_delay;
+ /** Calculated used time in units of 32 microseconds */
+ t_u16 used_time;
+ /** Calculated policed time in units of 32 microseconds */
+ t_u16 policed_time;
+ /** Queue Delay Histogram; number of packets per queue delay range
+ *
+ * [0] - 0ms <= delay < 5ms
+ * [1] - 5ms <= delay < 10ms
+ * [2] - 10ms <= delay < 20ms
+ * [3] - 20ms <= delay < 30ms
+ * [4] - 30ms <= delay < 40ms
+ * [5] - 40ms <= delay < 50ms
+ * [6] - 50ms <= delay < msduLifetime (TUs)
+ */
+ t_u16 delay_histogram[MLAN_WMM_STATS_PKTS_HIST_BINS];
+} wlan_ioctl_wmm_queue_stats_t,
+/** Type definition of mlan_ds_wmm_queue_stats for MLAN_OID_WMM_CFG_QUEUE_STATS */
+ mlan_ds_wmm_queue_stats, *pmlan_ds_wmm_queue_stats;
+
+/**
+ * @brief IOCTL sub structure for a specific WMM AC Status
+ */
+typedef struct
+{
+ /** WMM Acm */
+ t_u8 wmm_acm;
+ /** Flow required flag */
+ t_u8 flow_required;
+ /** Flow created flag */
+ t_u8 flow_created;
+ /** Disabled flag */
+ t_u8 disabled;
+} wlan_ioctl_wmm_queue_status_ac_t;
+
+/**
+ * @brief IOCTL structure to retrieve the WMM AC Queue status
+ *
+ * IOCTL structure from the application layer to retrieve:
+ * - ACM bit setting for the AC
+ * - Firmware status (flow required, flow created, flow disabled)
+ *
+ * @sa woal_wmm_queue_status_ioctl
+ */
+typedef struct
+{
+ /** WMM AC queue status */
+ wlan_ioctl_wmm_queue_status_ac_t ac_status[MLAN_WMM_MAX_AC_QUEUES];
+} wlan_ioctl_wmm_queue_status_t,
+/** Type definition of mlan_ds_wmm_queue_status for MLAN_OID_WMM_CFG_QUEUE_STATUS */
+ mlan_ds_wmm_queue_status, *pmlan_ds_wmm_queue_status;
+
+/** Type definition of mlan_ds_wmm_addts for MLAN_OID_WMM_CFG_ADDTS */
+typedef struct _mlan_ds_wmm_addts
+{
+ /** Result of ADDTS request */
+ mlan_cmd_result_e result;
+ /** Timeout value in milliseconds */
+ t_u32 timeout;
+ /** IEEE status code */
+ t_u32 status_code;
+ /** Dialog token */
+ t_u8 dialog_tok;
+ /** TSPEC data length */
+ t_u8 ie_data_len;
+ /** TSPEC to send in the ADDTS + buffering for any extra IEs */
+ t_u8 ie_data[MLAN_WMM_TSPEC_SIZE + MLAN_WMM_ADDTS_EXTRA_IE_BYTES];
+} mlan_ds_wmm_addts, *pmlan_ds_wmm_addts;
+
+/** Type definition of mlan_ds_wmm_delts for MLAN_OID_WMM_CFG_DELTS */
+typedef struct _mlan_ds_wmm_delts
+{
+ /** Result of DELTS request */
+ mlan_cmd_result_e result;
+ /** IEEE status code */
+ t_u32 status_code;
+ /** TSPEC data length */
+ t_u8 ie_data_len;
+ /** TSPEC to send in the DELTS */
+ t_u8 ie_data[MLAN_WMM_TSPEC_SIZE];
+} mlan_ds_wmm_delts, *pmlan_ds_wmm_delts;
+
+/** Type definition of mlan_ds_wmm_queue_config for MLAN_OID_WMM_CFG_QUEUE_CONFIG */
+typedef struct _mlan_ds_wmm_queue_config
+{
+ /** Action of Queue Config : Set, Get, or Default */
+ mlan_wmm_queue_config_action_e action;
+ /** WMM Access Category: WMM_AC_BK(0) to WMM_AC_VO(3) */
+ mlan_wmm_ac_e access_category;
+ /** Lifetime expiry in TUs */
+ t_u16 msdu_lifetime_expiry;
+ /** Reserve for future use */
+ t_u8 reserved[10];
+} mlan_ds_wmm_queue_config, *pmlan_ds_wmm_queue_config;
+
+/** Type definition of mlan_ds_wmm_cfg for MLAN_IOCTL_WMM_CFG */
+typedef struct _mlan_ds_wmm_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** WMM configuration parameter */
+ union
+ {
+ /** WMM enable for MLAN_OID_WMM_CFG_ENABLE */
+ t_u32 wmm_enable;
+ /** QoS configuration for MLAN_OID_WMM_CFG_QOS */
+ t_u8 qos_cfg;
+ /** WMM add TS for MLAN_OID_WMM_CFG_ADDTS */
+ mlan_ds_wmm_addts addts;
+ /** WMM delete TS for MLAN_OID_WMM_CFG_DELTS */
+ mlan_ds_wmm_delts delts;
+ /** WMM queue configuration for MLAN_OID_WMM_CFG_QUEUE_CONFIG */
+ mlan_ds_wmm_queue_config q_cfg;
+ /** WMM queue status for MLAN_OID_WMM_CFG_QUEUE_STATS */
+ mlan_ds_wmm_queue_stats q_stats;
+ /** WMM queue status for MLAN_OID_WMM_CFG_QUEUE_STATUS */
+ mlan_ds_wmm_queue_status q_status;
+ /** WMM TS status for MLAN_OID_WMM_CFG_TS_STATUS */
+ mlan_ds_wmm_ts_status ts_status;
+ } param;
+} mlan_ds_wmm_cfg, *pmlan_ds_wmm_cfg;
+
+/*-----------------------------------------------------------------*/
+/** WPS Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for WPS session */
+enum _mlan_wps_status
+{
+ MLAN_WPS_CFG_SESSION_START = 1,
+ MLAN_WPS_CFG_SESSION_END = 0
+};
+
+/** Type definition of mlan_ds_wps_cfg for MLAN_IOCTL_WPS_CFG */
+typedef struct _mlan_ds_wps_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** WPS configuration parameter */
+ union
+ {
+ /** WPS session for MLAN_OID_WPS_CFG_SESSION */
+ t_u32 wps_session;
+ } param;
+} mlan_ds_wps_cfg, *pmlan_ds_wps_cfg;
+
+/*-----------------------------------------------------------------*/
+/** 802.11n Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Maximum MCS */
+#define NUM_MCS_FIELD 16
+
+/** Supported stream modes */
+#define HT_STREAM_MODE_1X1 0x11
+#define HT_STREAM_MODE_2X2 0x22
+
+/* Both 2.4G and 5G band selected */
+#define BAND_SELECT_BOTH 0
+/* Band 2.4G selected */
+#define BAND_SELECT_BG 1
+/* Band 5G selected */
+#define BAND_SELECT_A 2
+
+/** Type definition of mlan_ds_11n_htcap_cfg for MLAN_OID_11N_HTCAP_CFG */
+typedef struct _mlan_ds_11n_htcap_cfg
+{
+ /** HT Capability information */
+ t_u32 htcap;
+ /** Band selection */
+ t_u32 misc_cfg;
+ /** Hardware HT cap information required */
+ t_u32 hw_cap_req;
+} mlan_ds_11n_htcap_cfg, *pmlan_ds_11n_htcap_cfg;
+
+/** Type definition of mlan_ds_11n_addba_param for MLAN_OID_11N_CFG_ADDBA_PARAM */
+typedef struct _mlan_ds_11n_addba_param
+{
+ /** Timeout */
+ t_u32 timeout;
+ /** Buffer size for ADDBA request */
+ t_u32 txwinsize;
+ /** Buffer size for ADDBA response */
+ t_u32 rxwinsize;
+ /** amsdu for ADDBA request */
+ t_u8 txamsdu;
+ /** amsdu for ADDBA response */
+ t_u8 rxamsdu;
+} mlan_ds_11n_addba_param, *pmlan_ds_11n_addba_param;
+
+/** Type definition of mlan_ds_11n_tx_cfg for MLAN_OID_11N_CFG_TX */
+typedef struct _mlan_ds_11n_tx_cfg
+{
+ /** HTTxCap */
+ t_u16 httxcap;
+ /** HTTxInfo */
+ t_u16 httxinfo;
+ /** Band selection */
+ t_u32 misc_cfg;
+} mlan_ds_11n_tx_cfg, *pmlan_ds_11n_tx_cfg;
+
+/** BF Global Configuration */
+#define BF_GLOBAL_CONFIGURATION 0x00
+/** Performs NDP sounding for PEER specified */
+#define TRIGGER_SOUNDING_FOR_PEER 0x01
+/** TX BF interval for channel sounding */
+#define SET_GET_BF_PERIODICITY 0x02
+/** Tell FW not to perform any sounding for peer */
+#define TX_BF_FOR_PEER_ENBL 0x03
+/** TX BF SNR threshold for peer */
+#define SET_SNR_THR_PEER 0x04
+
+/* Maximum number of peer MAC and status/SNR tuples */
+#define MAX_PEER_MAC_TUPLES 10
+
+/** Any new subcommand structure should be declare here */
+
+/** bf global cfg args */
+typedef struct _mlan_bf_global_cfg_args
+{
+ /** Global enable/disable bf */
+ t_u8 bf_enbl;
+ /** Global enable/disable sounding */
+ t_u8 sounding_enbl;
+ /** FB Type */
+ t_u8 fb_type;
+ /** SNR Threshold */
+ t_u8 snr_threshold;
+ /** Sounding interval in milliseconds */
+ t_u16 sounding_interval;
+ /** BF mode */
+ t_u8 bf_mode;
+ /** Reserved */
+ t_u8 reserved;
+} mlan_bf_global_cfg_args;
+
+/** trigger sounding args */
+typedef struct _mlan_trigger_sound_args
+{
+ /** Peer MAC address */
+ t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH];
+ /** Status */
+ t_u8 status;
+} mlan_trigger_sound_args;
+
+/** bf periodicity args */
+typedef struct _mlan_bf_periodicity_args
+{
+ /** Peer MAC address */
+ t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH];
+ /** Current Tx BF Interval in milliseconds */
+ t_u16 interval;
+ /** Status */
+ t_u8 status;
+} mlan_bf_periodicity_args;
+
+/** tx bf peer args */
+typedef struct _mlan_tx_bf_peer_args
+{
+ /** Peer MAC address */
+ t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH];
+ /** Reserved */
+ t_u16 reserved;
+ /** Enable/Disable Beamforming */
+ t_u8 bf_enbl;
+ /** Enable/Disable sounding */
+ t_u8 sounding_enbl;
+ /** FB Type */
+ t_u8 fb_type;
+} mlan_tx_bf_peer_args;
+
+/** SNR threshold args */
+typedef struct _mlan_snr_thr_args
+{
+ /** Peer MAC address */
+ t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH];
+ /** SNR for peer */
+ t_u8 snr;
+} mlan_snr_thr_args;
+
+/** Type definition of mlan_ds_11n_tx_bf_cfg for MLAN_OID_11N_CFG_TX_BF_CFG */
+typedef struct _mlan_ds_11n_tx_bf_cfg
+{
+ /** BF Action */
+ t_u16 bf_action;
+ /** Action */
+ t_u16 action;
+ /** Number of peers */
+ t_u32 no_of_peers;
+ union
+ {
+ mlan_bf_global_cfg_args bf_global_cfg;
+ mlan_trigger_sound_args bf_sound[MAX_PEER_MAC_TUPLES];
+ mlan_bf_periodicity_args bf_periodicity[MAX_PEER_MAC_TUPLES];
+ mlan_tx_bf_peer_args tx_bf_peer[MAX_PEER_MAC_TUPLES];
+ mlan_snr_thr_args bf_snr[MAX_PEER_MAC_TUPLES];
+ } body;
+} mlan_ds_11n_tx_bf_cfg, *pmlan_ds_11n_tx_bf_cfg;
+
+/** Type definition of mlan_ds_11n_amsdu_aggr_ctrl for
+ * MLAN_OID_11N_AMSDU_AGGR_CTRL*/
+typedef struct _mlan_ds_11n_amsdu_aggr_ctrl
+{
+ /** Enable/Disable */
+ t_u16 enable;
+ /** Current AMSDU size valid */
+ t_u16 curr_buf_size;
+} mlan_ds_11n_amsdu_aggr_ctrl, *pmlan_ds_11n_amsdu_aggr_ctrl;
+
+/** Type definition of mlan_ds_11n_aggr_prio_tbl for MLAN_OID_11N_CFG_AGGR_PRIO_TBL */
+typedef struct _mlan_ds_11n_aggr_prio_tbl
+{
+ /** ampdu priority table */
+ t_u8 ampdu[MAX_NUM_TID];
+ /** amsdu priority table */
+ t_u8 amsdu[MAX_NUM_TID];
+} mlan_ds_11n_aggr_prio_tbl, *pmlan_ds_11n_aggr_prio_tbl;
+
+/** Type definition of mlan_ds_11n_cfg for MLAN_IOCTL_11N_CFG */
+typedef struct _mlan_ds_11n_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** 802.11n configuration parameter */
+ union
+ {
+ /** Tx param for 11n for MLAN_OID_11N_CFG_TX */
+ mlan_ds_11n_tx_cfg tx_cfg;
+ /** Aggr priority table for MLAN_OID_11N_CFG_AGGR_PRIO_TBL */
+ mlan_ds_11n_aggr_prio_tbl aggr_prio_tbl;
+ /** Add BA param for MLAN_OID_11N_CFG_ADDBA_PARAM */
+ mlan_ds_11n_addba_param addba_param;
+ /** Add BA Reject paramters for MLAN_OID_11N_CFG_ADDBA_REJECT */
+ t_u8 addba_reject[MAX_NUM_TID];
+ /** Tx buf size for MLAN_OID_11N_CFG_MAX_TX_BUF_SIZE */
+ t_u32 tx_buf_size;
+ /** HT cap info configuration for MLAN_OID_11N_HTCAP_CFG */
+ mlan_ds_11n_htcap_cfg htcap_cfg;
+ /** Tx param for 11n for MLAN_OID_11N_AMSDU_AGGR_CTRL */
+ mlan_ds_11n_amsdu_aggr_ctrl amsdu_aggr_ctrl;
+ /** Supported MCS Set field */
+ t_u8 supported_mcs_set[NUM_MCS_FIELD];
+ /** Transmit Beamforming Capabilities field */
+ t_u32 tx_bf_cap;
+ /** Transmit Beamforming configuration */
+ mlan_ds_11n_tx_bf_cfg tx_bf;
+ /** HT stream configuration */
+ t_u32 stream_cfg;
+ } param;
+} mlan_ds_11n_cfg, *pmlan_ds_11n_cfg;
+
+/** Country code length */
+#define COUNTRY_CODE_LEN 3
+
+/*-----------------------------------------------------------------*/
+/** 802.11d Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Maximum subbands for 11d */
+#define MRVDRV_MAX_SUBBAND_802_11D 83
+
+#ifdef STA_SUPPORT
+/** Data structure for subband set */
+typedef struct _mlan_ds_subband_set_t
+{
+ /** First channel */
+ t_u8 first_chan;
+ /** Number of channels */
+ t_u8 no_of_chan;
+ /** Maximum Tx power in dBm */
+ t_u8 max_tx_pwr;
+} mlan_ds_subband_set_t;
+
+/** Domain regulatory information */
+typedef struct _mlan_ds_11d_domain_info
+{
+ /** Country Code */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ /** Band that channels in sub_band belong to */
+ t_u8 band;
+ /** No. of subband in below */
+ t_u8 no_of_sub_band;
+ /** Subband data to send/last sent */
+ mlan_ds_subband_set_t sub_band[MRVDRV_MAX_SUBBAND_802_11D];
+} mlan_ds_11d_domain_info;
+#endif
+
+/** Type definition of mlan_ds_11d_cfg for MLAN_IOCTL_11D_CFG */
+typedef struct _mlan_ds_11d_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** 802.11d configuration parameter */
+ union
+ {
+#ifdef STA_SUPPORT
+ /** Enable for MLAN_OID_11D_CFG_ENABLE */
+ t_u32 enable_11d;
+ /** Domain info for MLAN_OID_11D_DOMAIN_INFO */
+ mlan_ds_11d_domain_info domain_info;
+#endif /* STA_SUPPORT */
+#ifdef UAP_SUPPORT
+ /** tlv data for MLAN_OID_11D_DOMAIN_INFO */
+ t_u8 domain_tlv[MAX_IE_SIZE];
+#endif /* UAP_SUPPORT */
+ } param;
+} mlan_ds_11d_cfg, *pmlan_ds_11d_cfg;
+
+/*-----------------------------------------------------------------*/
+/** Register Memory Access Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for register type */
+enum _mlan_reg_type
+{
+ MLAN_REG_MAC = 1,
+ MLAN_REG_BBP,
+ MLAN_REG_RF,
+ MLAN_REG_CAU = 5,
+};
+
+/** Type definition of mlan_ds_reg_rw for MLAN_OID_REG_RW */
+typedef struct _mlan_ds_reg_rw
+{
+ /** Register type */
+ t_u32 type;
+ /** Offset */
+ t_u32 offset;
+ /** Value */
+ t_u32 value;
+} mlan_ds_reg_rw;
+
+/** Maximum EEPROM data */
+#define MAX_EEPROM_DATA 256
+
+/** Type definition of mlan_ds_read_eeprom for MLAN_OID_EEPROM_RD */
+typedef struct _mlan_ds_read_eeprom
+{
+ /** Multiples of 4 */
+ t_u16 offset;
+ /** Number of bytes */
+ t_u16 byte_count;
+ /** Value */
+ t_u8 value[MAX_EEPROM_DATA];
+} mlan_ds_read_eeprom;
+
+/** Type definition of mlan_ds_mem_rw for MLAN_OID_MEM_RW */
+typedef struct _mlan_ds_mem_rw
+{
+ /** Address */
+ t_u32 addr;
+ /** Value */
+ t_u32 value;
+} mlan_ds_mem_rw;
+
+/** Type definition of mlan_ds_reg_mem for MLAN_IOCTL_REG_MEM */
+typedef struct _mlan_ds_reg_mem
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Register memory access parameter */
+ union
+ {
+ /** Register access for MLAN_OID_REG_RW */
+ mlan_ds_reg_rw reg_rw;
+ /** EEPROM access for MLAN_OID_EEPROM_RD */
+ mlan_ds_read_eeprom rd_eeprom;
+ /** Memory access for MLAN_OID_MEM_RW */
+ mlan_ds_mem_rw mem_rw;
+ } param;
+} mlan_ds_reg_mem, *pmlan_ds_reg_mem;
+
+/*-----------------------------------------------------------------*/
+/** Multi-Radio Configuration Group */
+/*-----------------------------------------------------------------*/
+
+/*-----------------------------------------------------------------*/
+/** 802.11h Configuration Group */
+/*-----------------------------------------------------------------*/
+#if defined(DFS_TESTING_SUPPORT)
+/** Type definition of mlan_ds_11h_dfs_testing for MLAN_OID_11H_DFS_TESTING */
+typedef struct _mlan_ds_11h_dfs_testing
+{
+ /** User-configured CAC period in milliseconds, 0 to use default */
+ t_u16 usr_cac_period_msec;
+ /** User-configured NOP period in seconds, 0 to use default */
+ t_u16 usr_nop_period_sec;
+ /** User-configured skip channel change, 0 to disable */
+ t_u8 usr_no_chan_change;
+ /** User-configured fixed channel to change to, 0 to use random channel */
+ t_u8 usr_fixed_new_chan;
+} mlan_ds_11h_dfs_testing, *pmlan_ds_11h_dfs_testing;
+#endif
+
+/** Type definition of mlan_ds_11h_cfg for MLAN_IOCTL_11H_CFG */
+typedef struct _mlan_ds_11h_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ union
+ {
+ /** Local power constraint for MLAN_OID_11H_LOCAL_POWER_CONSTRAINT */
+ t_s8 usr_local_power_constraint;
+#if defined(DFS_TESTING_SUPPORT)
+ /** User-configuation for MLAN_OID_11H_DFS_TESTING */
+ mlan_ds_11h_dfs_testing dfs_testing;
+#endif
+ } param;
+} mlan_ds_11h_cfg, *pmlan_ds_11h_cfg;
+
+/*-----------------------------------------------------------------*/
+/** Miscellaneous Configuration Group */
+/*-----------------------------------------------------------------*/
+
+/** CMD buffer size */
+#define MLAN_SIZE_OF_CMD_BUFFER 2048
+
+/** LDO Internal */
+#define LDO_INTERNAL 0
+/** LDO External */
+#define LDO_EXTERNAL 1
+
+/** Enumeration for IE type */
+enum _mlan_ie_type
+{
+ MLAN_IE_TYPE_GEN_IE = 0,
+#ifdef STA_SUPPORT
+ MLAN_IE_TYPE_ARP_FILTER,
+#endif /* STA_SUPPORT */
+};
+
+/** Type definition of mlan_ds_misc_gen_ie for MLAN_OID_MISC_GEN_IE */
+typedef struct _mlan_ds_misc_gen_ie
+{
+ /** IE type */
+ t_u32 type;
+ /** IE length */
+ t_u32 len;
+ /** IE buffer */
+ t_u8 ie_data[MAX_IE_SIZE];
+} mlan_ds_misc_gen_ie;
+
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+/** Type definition of mlan_ds_misc_sdio_mpa_ctrl for MLAN_OID_MISC_SDIO_MPA_CTRL */
+typedef struct _mlan_ds_misc_sdio_mpa_ctrl
+{
+ /** SDIO MP-A TX enable/disable */
+ t_u16 tx_enable;
+ /** SDIO MP-A RX enable/disable */
+ t_u16 rx_enable;
+ /** SDIO MP-A TX buf size */
+ t_u16 tx_buf_size;
+ /** SDIO MP-A RX buf size */
+ t_u16 rx_buf_size;
+ /** SDIO MP-A TX Max Ports */
+ t_u16 tx_max_ports;
+ /** SDIO MP-A RX Max Ports */
+ t_u16 rx_max_ports;
+} mlan_ds_misc_sdio_mpa_ctrl;
+#endif
+
+/** Type definition of mlan_ds_misc_cmd for MLAN_OID_MISC_HOST_CMD */
+typedef struct _mlan_ds_misc_cmd
+{
+ /** Command length */
+ t_u32 len;
+ /** Command buffer */
+ t_u8 cmd[MLAN_SIZE_OF_CMD_BUFFER];
+} mlan_ds_misc_cmd;
+
+/** Maximum number of system clocks */
+#define MLAN_MAX_CLK_NUM 16
+
+/** Clock type : Configurable */
+#define MLAN_CLK_CONFIGURABLE 0
+/** Clock type : Supported */
+#define MLAN_CLK_SUPPORTED 1
+
+/** Type definition of mlan_ds_misc_sys_clock for MLAN_OID_MISC_SYS_CLOCK */
+typedef struct _mlan_ds_misc_sys_clock
+{
+ /** Current system clock */
+ t_u16 cur_sys_clk;
+ /** Clock type */
+ t_u16 sys_clk_type;
+ /** Number of clocks */
+ t_u16 sys_clk_num;
+ /** System clocks */
+ t_u16 sys_clk[MLAN_MAX_CLK_NUM];
+} mlan_ds_misc_sys_clock;
+
+/** Enumeration for function init/shutdown */
+enum _mlan_func_cmd
+{
+ MLAN_FUNC_INIT = 1,
+ MLAN_FUNC_SHUTDOWN,
+};
+
+/** Type definition of mlan_ds_misc_tx_datapause for MLAN_OID_MISC_TX_DATAPAUSE */
+typedef struct _mlan_ds_misc_tx_datapause
+{
+ /** Tx data pause flag */
+ t_u16 tx_pause;
+ /** Max number of Tx buffers for all PS clients */
+ t_u16 tx_buf_cnt;
+} mlan_ds_misc_tx_datapause;
+
+/** IP address length */
+#define IPADDR_LEN (16)
+/** Max number of ip */
+#define MAX_IPADDR (4)
+/** IP address type - IPv4*/
+#define IPADDR_TYPE_IPV4 (1)
+/** IP operation remove */
+#define MLAN_IPADDR_OP_IP_REMOVE (0)
+/** IP operation ARP filter */
+#define MLAN_IPADDR_OP_ARP_FILTER MBIT(0)
+/** IP operation ARP response */
+#define MLAN_IPADDR_OP_AUTO_ARP_RESP MBIT(1)
+
+/** Type definition of mlan_ds_misc_ipaddr_cfg for MLAN_OID_MISC_IP_ADDR */
+typedef struct _mlan_ds_misc_ipaddr_cfg
+{
+ /** Operation code */
+ t_u32 op_code;
+ /** IP address type */
+ t_u32 ip_addr_type;
+ /** Number of IP */
+ t_u32 ip_addr_num;
+ /** IP address */
+ t_u8 ip_addr[MAX_IPADDR][IPADDR_LEN];
+} mlan_ds_misc_ipaddr_cfg;
+
+/* MEF configuration disable */
+#define MEF_CFG_DISABLE 0
+/* MEF configuration Rx filter enable */
+#define MEF_CFG_RX_FILTER_ENABLE 1
+/* MEF configuration auto ARP response */
+#define MEF_CFG_AUTO_ARP_RESP 2
+/* MEF configuration host command */
+#define MEF_CFG_HOSTCMD 0xFFFF
+
+/** Type definition of mlan_ds_misc_mef_cfg for MLAN_OID_MISC_MEF_CFG */
+typedef struct _mlan_ds_misc_mef_cfg
+{
+ /** Sub-ID for operation */
+ t_u32 sub_id;
+ /** Parameter according to sub-ID */
+ union
+ {
+ /** MEF command buffer for MEF_CFG_HOSTCMD */
+ mlan_ds_misc_cmd cmd_buf;
+ } param;
+} mlan_ds_misc_mef_cfg;
+
+/** Type definition of mlan_ds_misc_cfp_code for MLAN_OID_MISC_CFP_CODE */
+typedef struct _mlan_ds_misc_cfp_code
+{
+ /** CFP table code for 2.4GHz */
+ t_u32 cfp_code_bg;
+ /** CFP table code for 5GHz */
+ t_u32 cfp_code_a;
+} mlan_ds_misc_cfp_code;
+
+/** Type definition of mlan_ds_misc_country_code for MLAN_OID_MISC_COUNTRY_CODE */
+typedef struct _mlan_ds_misc_country_code
+{
+ /** Country Code */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+} mlan_ds_misc_country_code;
+
+/** BITMAP for subscribe event rssi low */
+#define SUBSCRIBE_EVT_RSSI_LOW MBIT(0)
+/** BITMAP for subscribe event snr low */
+#define SUBSCRIBE_EVT_SNR_LOW MBIT(1)
+/** BITMAP for subscribe event max fail */
+#define SUBSCRIBE_EVT_MAX_FAIL MBIT(2)
+/** BITMAP for subscribe event beacon missed */
+#define SUBSCRIBE_EVT_BEACON_MISSED MBIT(3)
+/** BITMAP for subscribe event rssi high */
+#define SUBSCRIBE_EVT_RSSI_HIGH MBIT(4)
+/** BITMAP for subscribe event snr high */
+#define SUBSCRIBE_EVT_SNR_HIGH MBIT(5)
+/** BITMAP for subscribe event data rssi low */
+#define SUBSCRIBE_EVT_DATA_RSSI_LOW MBIT(6)
+/** BITMAP for subscribe event data snr low */
+#define SUBSCRIBE_EVT_DATA_SNR_LOW MBIT(7)
+/** BITMAP for subscribe event data rssi high */
+#define SUBSCRIBE_EVT_DATA_RSSI_HIGH MBIT(8)
+/** BITMAP for subscribe event data snr high */
+#define SUBSCRIBE_EVT_DATA_SNR_HIGH MBIT(9)
+/** BITMAP for subscribe event link quality */
+#define SUBSCRIBE_EVT_LINK_QUALITY MBIT(10)
+/** BITMAP for subscribe event pre_beacon_lost */
+#define SUBSCRIBE_EVT_PRE_BEACON_LOST MBIT(11)
+/** default PRE_BEACON_MISS_COUNT */
+#define DEFAULT_PRE_BEACON_MISS 30
+
+/** Type definition of mlan_ds_subscribe_evt for MLAN_OID_MISC_CFP_CODE */
+typedef struct _mlan_ds_subscribe_evt
+{
+ /** bitmap for subscribe event */
+ t_u16 evt_bitmap;
+ /** Absolute value of RSSI threshold value (dBm) */
+ t_u8 low_rssi;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 low_rssi_freq;
+ /** SNR threshold value (dB) */
+ t_u8 low_snr;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 low_snr_freq;
+ /** Failure count threshold */
+ t_u8 failure_count;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 failure_count_freq;
+ /** num of missed beacons */
+ t_u8 beacon_miss;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 beacon_miss_freq;
+ /** Absolute value of RSSI threshold value (dBm) */
+ t_u8 high_rssi;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 high_rssi_freq;
+ /** SNR threshold value (dB) */
+ t_u8 high_snr;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 high_snr_freq;
+ /** Absolute value of data RSSI threshold value (dBm) */
+ t_u8 data_low_rssi;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 data_low_rssi_freq;
+ /** Absolute value of data SNR threshold value (dBm) */
+ t_u8 data_low_snr;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 data_low_snr_freq;
+ /** Absolute value of data RSSI threshold value (dBm) */
+ t_u8 data_high_rssi;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 data_high_rssi_freq;
+ /** Absolute value of data SNR threshold value (dBm) */
+ t_u8 data_high_snr;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 data_high_snr_freq;
+ /* Link SNR threshold (dB) */
+ t_u16 link_snr;
+ /* Link SNR frequency */
+ t_u16 link_snr_freq;
+ /* Second minimum rate value as per the rate table below */
+ t_u16 link_rate;
+ /* Second minimum rate frequency */
+ t_u16 link_rate_freq;
+ /* Tx latency value (us) */
+ t_u16 link_tx_latency;
+ /* Tx latency frequency */
+ t_u16 link_tx_lantency_freq;
+ /* Number of pre missed beacons */
+ t_u8 pre_beacon_miss;
+} mlan_ds_subscribe_evt;
+
+/** Max OTP user data length */
+#define MAX_OTP_USER_DATA_LEN 252
+
+/** Type definition of mlan_ds_misc_otp_user_data for MLAN_OID_MISC_OTP_USER_DATA */
+typedef struct _mlan_ds_misc_otp_user_data
+{
+ /** Reserved */
+ t_u16 reserved;
+ /** OTP user data length */
+ t_u16 user_data_length;
+ /** User data buffer */
+ t_u8 user_data[MAX_OTP_USER_DATA_LEN];
+} mlan_ds_misc_otp_user_data;
+
+/** Type definition of mlan_ds_misc_cfg for MLAN_IOCTL_MISC_CFG */
+typedef struct _mlan_ds_misc_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Miscellaneous configuration parameter */
+ union
+ {
+ /** Generic IE for MLAN_OID_MISC_GEN_IE */
+ mlan_ds_misc_gen_ie gen_ie;
+ /** Region code for MLAN_OID_MISC_REGION */
+ t_u32 region_code;
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+ /** SDIO MP-A Ctrl command for MLAN_OID_MISC_SDIO_MPA_CTRL */
+ mlan_ds_misc_sdio_mpa_ctrl mpa_ctrl;
+#endif
+ /** Hostcmd for MLAN_OID_MISC_HOST_CMD */
+ mlan_ds_misc_cmd hostcmd;
+ /** System clock for MLAN_OID_MISC_SYS_CLOCK */
+ mlan_ds_misc_sys_clock sys_clock;
+ /** WWS set/get for MLAN_OID_MISC_WWS */
+ t_u32 wws_cfg;
+ /** Function init/shutdown for MLAN_OID_MISC_INIT_SHUTDOWN */
+ t_u32 func_init_shutdown;
+ /** Custom IE for MLAN_OID_MISC_CUSTOM_IE */
+ mlan_ds_misc_custom_ie cust_ie;
+ /** Tx data pause for MLAN_OID_MISC_TX_DATAPAUSE */
+ mlan_ds_misc_tx_datapause tx_datapause;
+ /** IP address configuration */
+ mlan_ds_misc_ipaddr_cfg ipaddr_cfg;
+ /** MAC control for MLAN_OID_MISC_MAC_CONTROL */
+ t_u32 mac_ctrl;
+ /** MEF configuration for MLAN_OID_MISC_MEF_CFG */
+ mlan_ds_misc_mef_cfg mef_cfg;
+ /** CFP code for MLAN_OID_MISC_CFP_CODE */
+ mlan_ds_misc_cfp_code cfp_code;
+ /** Country code for MLAN_OID_MISC_COUNTRY_CODE */
+ mlan_ds_misc_country_code country_code;
+ /** Thermal reading for MLAN_OID_MISC_THERMAL */
+ t_u32 thermal;
+ /** Mgmt subtype mask for MLAN_OID_MISC_RX_MGMT_IND */
+ t_u32 mgmt_subtype_mask;
+ /** subscribe event for MLAN_OID_MISC_SUBSCRIBE_EVENT */
+ mlan_ds_subscribe_evt subscribe_event;
+#ifdef DEBUG_LEVEL1
+ /** Driver debug bit masks */
+ t_u32 drvdbg;
+#endif
+ mlan_ds_misc_otp_user_data otp_user_data;
+ } param;
+} mlan_ds_misc_cfg, *pmlan_ds_misc_cfg;
+
+#endif /* !_MLAN_IOCTL_H_ */
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_cfg80211.c b/drivers/net/wireless/sd8797/mlinux/moal_cfg80211.c
index 1b04db6b4da0..6b2a01f5c218 100644
--- a/drivers/net/wireless/sd8797/mlinux/moal_cfg80211.c
+++ b/drivers/net/wireless/sd8797/mlinux/moal_cfg80211.c
@@ -164,6 +164,19 @@ woal_get_wiphy_priv(struct wiphy *wiphy)
}
/**
+ * @brief Get the private structure from net device
+ *
+ * @param wiphy A pointer to net_device structure
+ *
+ * @return Pointer to moal_private
+ */
+void *
+woal_get_netdev_priv(struct net_device *dev)
+{
+ return (void *) netdev_priv(dev);
+}
+
+/**
* @brief Set/Enable encryption key
*
* @param priv A pointer to moal_private structure
@@ -270,8 +283,12 @@ woal_cfg80211_set_key(moal_private * priv, t_u8 is_enable_wep,
}
}
} else {
- sec->param.encrypt_key.key_remove = MTRUE;
- sec->param.encrypt_key.key_index = key_index;
+ if (key_index == KEY_INDEX_CLEAR_ALL)
+ sec->param.encrypt_key.key_disable = MTRUE;
+ else {
+ sec->param.encrypt_key.key_remove = MTRUE;
+ sec->param.encrypt_key.key_index = key_index;
+ }
sec->param.encrypt_key.key_flags = KEY_FLAG_REMOVE_KEY;
if (addr)
memcpy(sec->param.encrypt_key.mac_addr, addr, ETH_ALEN);
@@ -343,96 +360,30 @@ static int
woal_cfg80211_bss_role_cfg(moal_private * priv, t_u16 action, t_u8 * bss_role)
{
int ret = 0;
- mlan_ds_bss *bss = NULL;
- mlan_ioctl_req *req = NULL;
- struct net_device *dev = priv->netdev;
ENTER();
- req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
- if (req == NULL) {
- ret = -ENOMEM;
- goto done;
- }
- bss = (mlan_ds_bss *) req->pbuf;
- bss->sub_command = MLAN_OID_BSS_ROLE;
- req->req_id = MLAN_IOCTL_BSS;
- req->action = action;
- bss->param.bss_role = *bss_role;
-
- if (req->action == MLAN_ACT_SET) {
+ if (action == MLAN_ACT_SET) {
/* Reset interface */
woal_reset_intf(priv, MOAL_IOCTL_WAIT, MFALSE);
}
- if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_bss_role_cfg(priv, action, MOAL_IOCTL_WAIT, bss_role)) {
ret = -EFAULT;
goto done;
}
- if (req->action == MLAN_ACT_GET) {
- *bss_role = bss->param.bss_role;
- } else {
- /* Update moal_private */
- priv->bss_role = *bss_role;
- if (priv->bss_type == MLAN_BSS_TYPE_UAP)
- priv->bss_type = MLAN_BSS_TYPE_STA;
- else if (priv->bss_type == MLAN_BSS_TYPE_STA)
- priv->bss_type = MLAN_BSS_TYPE_UAP;
-
+ if (action == MLAN_ACT_SET) {
/* Initialize private structures */
woal_init_priv(priv, MOAL_IOCTL_WAIT);
- if (*bss_role == MLAN_BSS_ROLE_UAP) {
- /* Switch: STA -> uAP */
- /* Setup the OS Interface to our functions */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
- dev->do_ioctl = woal_uap_do_ioctl;
- dev->set_multicast_list = woal_uap_set_multicast_list;
-#else
- dev->netdev_ops = &woal_uap_netdev_ops;
-#endif
-#ifdef WIRELESS_EXT
-#ifdef UAP_WEXT
- if (IS_UAP_WEXT(cfg80211_wext)) {
-#if WIRELESS_EXT < 21
- dev->get_wireless_stats = woal_get_uap_wireless_stats;
-#endif
- dev->wireless_handlers =
- (struct iw_handler_def *) &woal_uap_handler_def;
- init_waitqueue_head(&priv->w_stats_wait_q);
- }
-#endif /* UAP_WEXT */
-#endif /* WIRELESS_EXT */
- } else if (*bss_role == MLAN_BSS_ROLE_STA) {
- /* Switch: uAP -> STA */
- /* Setup the OS Interface to our functions */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
- dev->do_ioctl = woal_do_ioctl;
- dev->set_multicast_list = woal_set_multicast_list;
-#else
- dev->netdev_ops = &woal_netdev_ops;
-#endif
-#ifdef WIRELESS_EXT
-#ifdef STA_WEXT
- if (IS_STA_WEXT(cfg80211_wext)) {
-#if WIRELESS_EXT < 21
- dev->get_wireless_stats = woal_get_wireless_stats;
-#endif
- dev->wireless_handlers =
- (struct iw_handler_def *) &woal_handler_def;
- init_waitqueue_head(&priv->w_stats_wait_q);
- }
-#endif /* STA_WEXT */
-#endif
- }
/* Enable interfaces */
- netif_device_attach(dev);
- woal_start_queue(dev);
+ netif_device_attach(priv->netdev);
+ woal_start_queue(priv->netdev);
}
done:
- if (req)
- kfree(req);
LEAVE();
return ret;
}
@@ -478,8 +429,7 @@ woal_cfg80211_init_p2p_client(moal_private * priv)
wifi_direct_mode = WIFI_DIRECT_MODE_DISABLE;
if (MLAN_STATUS_SUCCESS !=
- woal_cfg80211_wifi_direct_mode_cfg(priv,
- MLAN_ACT_SET, &wifi_direct_mode)) {
+ woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) {
ret = -EFAULT;
goto done;
}
@@ -487,8 +437,7 @@ woal_cfg80211_init_p2p_client(moal_private * priv)
/* first, init wifi direct to listen mode */
wifi_direct_mode = WIFI_DIRECT_MODE_LISTEN;
if (MLAN_STATUS_SUCCESS !=
- woal_cfg80211_wifi_direct_mode_cfg(priv, MLAN_ACT_SET,
- &wifi_direct_mode)) {
+ woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) {
ret = -EFAULT;
goto done;
}
@@ -496,8 +445,7 @@ woal_cfg80211_init_p2p_client(moal_private * priv)
/* second, init wifi direct client */
wifi_direct_mode = WIFI_DIRECT_MODE_CLIENT;
if (MLAN_STATUS_SUCCESS !=
- woal_cfg80211_wifi_direct_mode_cfg(priv,
- MLAN_ACT_SET, &wifi_direct_mode)) {
+ woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) {
ret = -EFAULT;
goto done;
}
@@ -531,8 +479,7 @@ woal_cfg80211_init_p2p_go(moal_private * priv)
wifi_direct_mode = WIFI_DIRECT_MODE_DISABLE;
if (MLAN_STATUS_SUCCESS !=
- woal_cfg80211_wifi_direct_mode_cfg(priv,
- MLAN_ACT_SET, &wifi_direct_mode)) {
+ woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) {
ret = -EFAULT;
goto done;
}
@@ -540,8 +487,7 @@ woal_cfg80211_init_p2p_go(moal_private * priv)
/* first, init wifi direct to listen mode */
wifi_direct_mode = WIFI_DIRECT_MODE_LISTEN;
if (MLAN_STATUS_SUCCESS !=
- woal_cfg80211_wifi_direct_mode_cfg(priv, MLAN_ACT_SET,
- &wifi_direct_mode)) {
+ woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) {
ret = -EFAULT;
goto done;
}
@@ -549,8 +495,7 @@ woal_cfg80211_init_p2p_go(moal_private * priv)
/* second, init wifi direct to GO mode */
wifi_direct_mode = WIFI_DIRECT_MODE_GO;
if (MLAN_STATUS_SUCCESS !=
- woal_cfg80211_wifi_direct_mode_cfg(priv,
- MLAN_ACT_SET, &wifi_direct_mode)) {
+ woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) {
ret = -EFAULT;
goto done;
}
@@ -603,8 +548,7 @@ woal_cfg80211_deinit_p2p(moal_private * priv)
/* cancel previous remain on channel */
if (priv->phandle->remain_on_channel) {
if (woal_cfg80211_remain_on_channel_cfg
- (priv->wdev->wiphy, MOAL_IOCTL_WAIT, MTRUE, &channel_status, NULL,
- 0, 0)) {
+ (priv, MOAL_IOCTL_WAIT, MTRUE, &channel_status, NULL, 0, 0)) {
PRINTM(MERROR, "Fail to cancel remain on channel\n");
ret = -EFAULT;
goto done;
@@ -640,8 +584,7 @@ woal_cfg80211_deinit_p2p(moal_private * priv)
wifi_direct_mode = WIFI_DIRECT_MODE_DISABLE;
if (MLAN_STATUS_SUCCESS !=
- woal_cfg80211_wifi_direct_mode_cfg(priv,
- MLAN_ACT_SET, &wifi_direct_mode)) {
+ woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) {
ret = -EFAULT;
goto done;
}
@@ -670,7 +613,7 @@ woal_cfg80211_change_virtual_intf(struct wiphy *wiphy,
struct vif_params *params)
{
int ret = 0;
- moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(dev);
mlan_ds_bss *bss = NULL;
mlan_ioctl_req *req = NULL;
@@ -687,7 +630,7 @@ woal_cfg80211_change_virtual_intf(struct wiphy *wiphy,
if (priv->phandle->remain_on_channel) {
t_u8 channel_status;
if (woal_cfg80211_remain_on_channel_cfg
- (wiphy, MOAL_IOCTL_WAIT, MTRUE, &channel_status, NULL, 0, 0)) {
+ (priv, MOAL_IOCTL_WAIT, MTRUE, &channel_status, NULL, 0, 0)) {
PRINTM(MERROR, "Fail to cancel remain on channel\n");
ret = -EFAULT;
goto done;
@@ -908,7 +851,7 @@ woal_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev,
#endif
const t_u8 * mac_addr, struct key_params *params)
{
- moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(netdev);
ENTER();
@@ -945,7 +888,7 @@ woal_cfg80211_del_key(struct wiphy *wiphy, struct net_device *netdev,
#endif
const t_u8 * mac_addr)
{
- moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(netdev);
ENTER();
@@ -981,7 +924,7 @@ woal_cfg80211_set_default_key(struct wiphy *wiphy,
)
{
int ret = 0;
- moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(netdev);
mlan_bss_info bss_info;
ENTER();
@@ -1019,9 +962,15 @@ woal_cfg80211_set_channel(struct wiphy *wiphy,
enum nl80211_channel_type channel_type)
{
int ret = 0;
- moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ moal_private *priv = NULL;
ENTER();
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34) || defined(COMPAT_WIRELESS)
+ if (dev)
+ priv = woal_get_netdev_priv(dev);
+ else
+#endif
+ priv = (moal_private *) woal_get_wiphy_priv(wiphy);
#ifdef STA_CFG80211
#ifdef STA_SUPPORT
if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
@@ -1031,7 +980,7 @@ woal_cfg80211_set_channel(struct wiphy *wiphy,
LEAVE();
return -EINVAL;
}
- ret = woal_set_rf_channel(wiphy, chan, channel_type);
+ ret = woal_set_rf_channel(priv, chan, channel_type);
}
#endif
#endif
@@ -1055,7 +1004,7 @@ woal_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
struct net_device *dev, u16 frame_type,
bool reg)
{
- moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(dev);
mlan_status status = MLAN_STATUS_SUCCESS;
t_u32 mgmt_subtype_mask = 0x0;
static t_u32 last_mgmt_subtype_mask = 0x0;
@@ -1112,7 +1061,7 @@ woal_cfg80211_mgmt_tx(struct wiphy *wiphy,
#endif
u64 * cookie)
{
- moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(dev);
int ret = 0;
pmlan_buffer pmbuf = NULL;
mlan_status status = MLAN_STATUS_SUCCESS;
@@ -1151,7 +1100,7 @@ woal_cfg80211_mgmt_tx(struct wiphy *wiphy,
/** cancel previous remain on channel */
if (priv->phandle->remain_on_channel) {
if (woal_cfg80211_remain_on_channel_cfg
- (wiphy, MOAL_IOCTL_WAIT, MTRUE, &channel_status, NULL, 0, 0)) {
+ (priv, MOAL_IOCTL_WAIT, MTRUE, &channel_status, NULL, 0, 0)) {
PRINTM(MERROR, "Fail to cancel remain on channel\n");
ret = -EFAULT;
goto done;
@@ -1171,13 +1120,13 @@ woal_cfg80211_mgmt_tx(struct wiphy *wiphy,
duration = MGMT_TX_DEFAULT_WAIT_TIME;
if (channel_type_valid)
ret =
- woal_cfg80211_remain_on_channel_cfg(wiphy, MOAL_IOCTL_WAIT,
+ woal_cfg80211_remain_on_channel_cfg(priv, MOAL_IOCTL_WAIT,
MFALSE, &channel_status,
chan, channel_type,
duration);
else
ret =
- woal_cfg80211_remain_on_channel_cfg(wiphy, MOAL_IOCTL_WAIT,
+ woal_cfg80211_remain_on_channel_cfg(priv, MOAL_IOCTL_WAIT,
MFALSE, &channel_status,
chan, 0, duration);
if (ret) {
@@ -1261,3 +1210,478 @@ woal_cfg80211_mgmt_tx(struct wiphy *wiphy,
LEAVE();
return ret;
}
+
+/**
+ * @brief Look up specific IE in a buf
+ *
+ * @param ie Pointer to IEs
+ * @param len Total length of ie
+ * @param id Element id to lookup
+ *
+ * @return Pointer of the specific IE -- success, NULL -- fail
+ */
+const t_u8 *
+woal_parse_ie_tlv(const t_u8 * ie, int len, t_u8 id)
+{
+ int left_len = len;
+ const t_u8 *pos = ie;
+ int length;
+
+ /* IE format: | u8 | id | | u8 | len | | var | data | */
+ while (left_len >= 2) {
+ length = *(pos + 1);
+ if ((*pos == id) && (length + 2) <= left_len)
+ return pos;
+ pos += (length + 2);
+ left_len -= (length + 2);
+ }
+
+ return NULL;
+}
+
+/**
+ * @brief This function returns priv
+ * based on mgmt ie index
+ *
+ * @param handle A pointer to moal_handle
+ * @param index mgmt ie index
+ *
+ * @return Pointer to moal_private
+ */
+static moal_private *
+woal_get_priv_by_mgmt_index(moal_handle * handle, t_u16 index)
+{
+ int i;
+
+ for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) {
+ if (handle->priv[i]) {
+ if (handle->priv[i]->probereq_index == index)
+ return (handle->priv[i]);
+ }
+ }
+ return NULL;
+}
+
+/**
+ * @brief Add custom ie to mgmt frames.
+ *
+ * @param priv A pointer to moal private structure
+ * @param beacon_ies_data Beacon ie
+ * @param beacon_index The index for beacon when auto index
+ * @param proberesp_ies_data Probe resp ie
+ * @param proberesp_index The index for probe resp when auto index
+ * @param assocresp_ies_data Assoc resp ie
+ * @param assocresp_index The index for assoc resp when auto index
+ * @param probereq_ies_data Probe req ie
+ * @param probereq_index The index for probe req when auto index *
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_cfg80211_custom_ie(moal_private * priv,
+ custom_ie * beacon_ies_data, t_u16 * beacon_index,
+ custom_ie * proberesp_ies_data, t_u16 * proberesp_index,
+ custom_ie * assocresp_ies_data, t_u16 * assocresp_index,
+ custom_ie * probereq_ies_data, t_u16 * probereq_index)
+{
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ds_misc_custom_ie *custom_ie = NULL;
+ t_u8 *pos = NULL;
+ t_u16 len = 0;
+ int ret = 0;
+
+ ENTER();
+
+ if (!(custom_ie = kmalloc(sizeof(mlan_ds_misc_custom_ie), GFP_KERNEL))) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ memset(custom_ie, 0x00, sizeof(mlan_ds_misc_custom_ie));
+ custom_ie->type = TLV_TYPE_MGMT_IE;
+
+ pos = (t_u8 *) custom_ie->ie_data_list;
+ if (beacon_ies_data) {
+ len = sizeof(*beacon_ies_data) - MAX_IE_SIZE
+ + beacon_ies_data->ie_length;
+ memcpy(pos, beacon_ies_data, len);
+ pos += len;
+ custom_ie->len += len;
+ }
+
+ if (proberesp_ies_data) {
+ len = sizeof(*proberesp_ies_data) - MAX_IE_SIZE
+ + proberesp_ies_data->ie_length;
+ memcpy(pos, proberesp_ies_data, len);
+ pos += len;
+ custom_ie->len += len;
+ }
+
+ if (assocresp_ies_data) {
+ len = sizeof(*assocresp_ies_data) - MAX_IE_SIZE
+ + assocresp_ies_data->ie_length;
+ memcpy(pos, assocresp_ies_data, len);
+ custom_ie->len += len;
+ }
+
+ if (probereq_ies_data) {
+ len = sizeof(*probereq_ies_data) - MAX_IE_SIZE
+ + probereq_ies_data->ie_length;
+ memcpy(pos, probereq_ies_data, len);
+ pos += len;
+ custom_ie->len += len;
+ }
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ misc = (mlan_ds_misc_cfg *) ioctl_req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_CUSTOM_IE;
+ ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
+ ioctl_req->action = MLAN_ACT_SET;
+
+ memcpy(&misc->param.cust_ie, custom_ie, sizeof(mlan_ds_misc_custom_ie));
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* get the assigned index */
+ pos = (t_u8 *) (&misc->param.cust_ie.ie_data_list[0].ie_index);
+ if (beacon_ies_data && beacon_ies_data->ie_length
+ && beacon_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
+ /* save beacon ie index after auto-indexing */
+ *beacon_index = misc->param.cust_ie.ie_data_list[0].ie_index;
+ len = sizeof(*beacon_ies_data) - MAX_IE_SIZE
+ + beacon_ies_data->ie_length;
+ pos += len;
+ }
+
+ if (proberesp_ies_data && proberesp_ies_data->ie_length
+ && proberesp_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
+ /* save probe resp ie index after auto-indexing */
+ *proberesp_index = *((t_u16 *) pos);
+ len = sizeof(*proberesp_ies_data) - MAX_IE_SIZE
+ + proberesp_ies_data->ie_length;
+ pos += len;
+ }
+
+ if (assocresp_ies_data && assocresp_ies_data->ie_length
+ && assocresp_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
+ /* save assoc resp ie index after auto-indexing */
+ *assocresp_index = *((t_u16 *) pos);
+ len = sizeof(*assocresp_ies_data) - MAX_IE_SIZE
+ + assocresp_ies_data->ie_length;
+ pos += len;
+ }
+ if (probereq_ies_data && probereq_ies_data->ie_length
+ && probereq_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
+ /* save probe resp ie index after auto-indexing */
+ *probereq_index = *((t_u16 *) pos);
+ len = sizeof(*probereq_ies_data) - MAX_IE_SIZE
+ + probereq_ies_data->ie_length;
+ pos += len;
+ }
+
+ if (ioctl_req->status_code == MLAN_ERROR_IOCTL_FAIL)
+ ret = -EFAULT;
+
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ if (custom_ie)
+ kfree(custom_ie);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Filter specific IE in ie buf
+ *
+ * @param ie Pointer to IEs
+ * @param len Total length of ie
+ * @param ie_out Pointer to out IE buf
+ *
+ * @return out IE length
+ */
+static t_u16
+woal_filter_beacon_ies(const t_u8 * ie, int len, t_u8 * ie_out)
+{
+ int left_len = len;
+ const t_u8 *pos = ie;
+ int length;
+ t_u8 id = 0;
+ t_u16 out_len = 0;
+
+ /* ERP_INFO and RSN IE will be fileter out */
+ while (left_len >= 2) {
+ length = *(pos + 1);
+ id = *pos;
+ if ((length + 2) > left_len)
+ break;
+ switch (id) {
+ case WLAN_EID_ERP_INFO:
+ case RSN_IE:
+ break;
+ default:
+ memcpy(ie_out + out_len, pos, length + 2);
+ out_len += length + 2;
+ break;
+ }
+ pos += (length + 2);
+ left_len -= (length + 2);
+ }
+ return out_len;
+}
+
+/**
+ * @brief config AP or GO for mgmt frame ies.
+ *
+ * @param priv A pointer to moal private structure
+ * @param beacon_ies A pointer to beacon ies
+ * @param beacon_ies_len Beacon ies length
+ * @param proberesp_ies A pointer to probe resp ies
+ * @param proberesp_ies_len Probe resp ies length
+ * @param assocresp_ies A pointer to probe resp ies
+ * @param assocresp_ies_len Assoc resp ies length
+ * @param probereq_ies A pointer to probe req ies
+ * @param probereq_ies_len Probe req ies length *
+ * @param mask Mgmt frame mask
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int
+woal_cfg80211_mgmt_frame_ie(moal_private * priv,
+ const t_u8 * beacon_ies, size_t beacon_ies_len,
+ const t_u8 * proberesp_ies,
+ size_t proberesp_ies_len,
+ const t_u8 * assocresp_ies,
+ size_t assocresp_ies_len, const t_u8 * probereq_ies,
+ size_t probereq_ies_len, t_u16 mask)
+{
+ int ret = 0;
+ t_u8 *pos = NULL;
+ custom_ie *beacon_ies_data = NULL;
+ custom_ie *proberesp_ies_data = NULL;
+ custom_ie *assocresp_ies_data = NULL;
+ custom_ie *probereq_ies_data = NULL;
+
+ /* static variables for mgmt frame ie auto-indexing */
+ static t_u16 beacon_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ static t_u16 proberesp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ static t_u16 assocresp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ static t_u16 probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ moal_private *pmpriv = NULL;
+ static t_u16 rsn_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ const t_u8 *rsn_ie;
+
+ ENTER();
+
+ if (mask & MGMT_MASK_BEACON) {
+ if (!(beacon_ies_data = kmalloc(sizeof(custom_ie), GFP_KERNEL))) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ if (beacon_ies && beacon_ies_len) {
+ rsn_ie =
+ woal_parse_ie_tlv((t_u8 *) beacon_ies, (int) beacon_ies_len,
+ RSN_IE);
+ if (rsn_ie) {
+ beacon_ies_data->ie_index = rsn_index;
+ beacon_ies_data->mgmt_subtype_mask =
+ MGMT_MASK_BEACON | MGMT_MASK_PROBE_RESP |
+ MGMT_MASK_ASSOC_RESP;
+ beacon_ies_data->ie_length = rsn_ie[1] + 2;
+ memcpy(beacon_ies_data->ie_buffer, rsn_ie, rsn_ie[1] + 2);
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_custom_ie(priv, beacon_ies_data, &rsn_index,
+ NULL, &proberesp_index, NULL,
+ &assocresp_index, NULL,
+ &probereq_index)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ } else {
+ /* clear rsn_ie */
+ if (rsn_index <= MAX_MGMT_IE_INDEX) {
+ beacon_ies_data->ie_index = rsn_index;
+ beacon_ies_data->mgmt_subtype_mask = MLAN_CUSTOM_IE_DELETE_MASK;
+ beacon_ies_data->ie_length = 0;
+ rsn_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_custom_ie(priv, beacon_ies_data, &rsn_index,
+ NULL, &proberesp_index, NULL,
+ &assocresp_index, NULL,
+ &probereq_index)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ }
+ }
+
+ if (mask & MGMT_MASK_PROBE_RESP) {
+ if (!(proberesp_ies_data = kmalloc(sizeof(custom_ie), GFP_KERNEL))) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ }
+
+ if (mask & MGMT_MASK_ASSOC_RESP) {
+ if (!(assocresp_ies_data = kmalloc(sizeof(custom_ie), GFP_KERNEL))) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ }
+ if (mask & MGMT_MASK_PROBE_REQ) {
+ if (!(probereq_ies_data = kmalloc(sizeof(custom_ie), GFP_KERNEL))) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ }
+
+ if (beacon_ies_data) {
+ memset(beacon_ies_data, 0x00, sizeof(custom_ie));
+ if (beacon_ies && beacon_ies_len) {
+ /* set the beacon ies */
+ beacon_ies_data->ie_index = beacon_index;
+ beacon_ies_data->mgmt_subtype_mask = MGMT_MASK_BEACON;
+ beacon_ies_data->mgmt_subtype_mask |= MGMT_MASK_ASSOC_RESP;
+ beacon_ies_data->ie_length = woal_filter_beacon_ies(beacon_ies,
+ beacon_ies_len,
+ beacon_ies_data->
+ ie_buffer);
+ } else {
+ /* clear the beacon ies */
+ if (beacon_index > MAX_MGMT_IE_INDEX) {
+ PRINTM(MERROR, "Invalid beacon index for mgmt frame ie.\n");
+ goto done;
+ }
+
+ beacon_ies_data->ie_index = beacon_index;
+ beacon_ies_data->mgmt_subtype_mask = MLAN_CUSTOM_IE_DELETE_MASK;
+ beacon_ies_data->ie_length = 0;
+ beacon_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ }
+ }
+
+ if (proberesp_ies_data) {
+ memset(proberesp_ies_data, 0x00, sizeof(custom_ie));
+ if (proberesp_ies && proberesp_ies_len) {
+ /* set the probe response ies */
+ // proberesp_ies_data->ie_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ proberesp_ies_data->ie_index = proberesp_index;
+ proberesp_ies_data->mgmt_subtype_mask = MGMT_MASK_PROBE_RESP;
+ proberesp_ies_data->ie_length = proberesp_ies_len;
+ pos = proberesp_ies_data->ie_buffer;
+ memcpy(pos, proberesp_ies, proberesp_ies_len);
+ } else {
+ /* clear the probe response ies */
+ if (proberesp_index > MAX_MGMT_IE_INDEX) {
+ PRINTM(MERROR, "Invalid probe resp index for mgmt frame ie.\n");
+ goto done;
+ }
+
+ proberesp_ies_data->ie_index = proberesp_index;
+ proberesp_ies_data->mgmt_subtype_mask = MLAN_CUSTOM_IE_DELETE_MASK;
+ proberesp_ies_data->ie_length = 0;
+ proberesp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ }
+ }
+ if (assocresp_ies_data) {
+ memset(assocresp_ies_data, 0x00, sizeof(custom_ie));
+ if (assocresp_ies && assocresp_ies_len) {
+ /* set the assoc response ies */
+ assocresp_ies_data->ie_index = assocresp_index;
+ assocresp_ies_data->mgmt_subtype_mask = MGMT_MASK_ASSOC_RESP;
+ assocresp_ies_data->ie_length = assocresp_ies_len;
+ pos = assocresp_ies_data->ie_buffer;
+ memcpy(pos, assocresp_ies, assocresp_ies_len);
+ } else {
+ /* clear the assoc response ies */
+ if (assocresp_index > MAX_MGMT_IE_INDEX) {
+ PRINTM(MERROR, "Invalid assoc resp index for mgmt frame ie.\n");
+ goto done;
+ }
+
+ assocresp_ies_data->ie_index = assocresp_index;
+ assocresp_ies_data->mgmt_subtype_mask = MLAN_CUSTOM_IE_DELETE_MASK;
+ assocresp_ies_data->ie_length = 0;
+ assocresp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ }
+ }
+
+ if (probereq_ies_data) {
+ memset(probereq_ies_data, 0x00, sizeof(custom_ie));
+ if ((probereq_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK) &&
+ (priv->probereq_index != probereq_index)) {
+ pmpriv = woal_get_priv_by_mgmt_index(priv->phandle, probereq_index);
+ if (pmpriv) {
+ probereq_ies_data->ie_index = probereq_index;
+ probereq_ies_data->mgmt_subtype_mask =
+ MLAN_CUSTOM_IE_DELETE_MASK;
+ probereq_ies_data->ie_length = 0;
+ probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ pmpriv->probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_custom_ie(pmpriv, NULL, &beacon_index,
+ NULL, &proberesp_index,
+ NULL, &assocresp_index,
+ probereq_ies_data,
+ &probereq_index)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ memset(probereq_ies_data, 0x00, sizeof(custom_ie));
+ }
+ }
+ if (probereq_ies && probereq_ies_len) {
+ /* set the probe req ies */
+ probereq_ies_data->ie_index = probereq_index;
+ probereq_ies_data->mgmt_subtype_mask = MGMT_MASK_PROBE_REQ;
+ probereq_ies_data->ie_length = probereq_ies_len;
+ pos = probereq_ies_data->ie_buffer;
+ memcpy(pos, probereq_ies, probereq_ies_len);
+ } else {
+ /* clear the probe req ies */
+ if (probereq_index > MAX_MGMT_IE_INDEX) {
+ PRINTM(MERROR, "Invalid probe resp index for mgmt frame ie.\n");
+ goto done;
+ }
+ probereq_ies_data->ie_index = probereq_index;
+ probereq_ies_data->mgmt_subtype_mask = MLAN_CUSTOM_IE_DELETE_MASK;
+ probereq_ies_data->ie_length = 0;
+ probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ }
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_custom_ie(priv, beacon_ies_data, &beacon_index,
+ proberesp_ies_data, &proberesp_index,
+ assocresp_ies_data, &assocresp_index,
+ probereq_ies_data, &probereq_index)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (probereq_ies_data)
+ priv->probereq_index = probereq_index;
+
+ done:
+ if (beacon_ies_data)
+ kfree(beacon_ies_data);
+ if (proberesp_ies_data)
+ kfree(proberesp_ies_data);
+ if (assocresp_ies_data)
+ kfree(assocresp_ies_data);
+
+ LEAVE();
+
+ return ret;
+}
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_cfg80211.h b/drivers/net/wireless/sd8797/mlinux/moal_cfg80211.h
index e1683ed08a89..f58fc18829fa 100644
--- a/drivers/net/wireless/sd8797/mlinux/moal_cfg80211.h
+++ b/drivers/net/wireless/sd8797/mlinux/moal_cfg80211.h
@@ -24,8 +24,11 @@
#include "moal_main.h"
+/* Clear all key indexes */
+#define KEY_INDEX_CLEAR_ALL (0x0000000F)
+
/** RTS/FRAG disabled value */
-#define MLAN_FRAG_RTS_DISABLED (0xFFFFFFFF)
+#define MLAN_FRAG_RTS_DISABLED (0xFFFFFFFF)
#ifndef WLAN_CIPHER_SUITE_WAPI
#define WLAN_CIPHER_SUITE_WAPI 0x00000020
@@ -55,6 +58,9 @@ static const void *const mrvl_wiphy_privid = &mrvl_wiphy_privid;
/* Get the private structure from wiphy */
void *woal_get_wiphy_priv(struct wiphy *wiphy);
+/* Get the private structure from net device */
+void *woal_get_netdev_priv(struct net_device *dev);
+
int woal_cfg80211_change_virtual_intf(struct wiphy *wiphy,
struct net_device *dev,
enum nl80211_iftype type,
@@ -78,7 +84,7 @@ int woal_cfg80211_del_key(struct wiphy *wiphy,
#ifdef STA_CFG80211
#ifdef STA_SUPPORT
-int woal_set_rf_channel(struct wiphy *wiphy,
+int woal_set_rf_channel(moal_private * priv,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type);
mlan_status woal_inform_bss_from_scan_result(moal_private * priv,
@@ -149,7 +155,7 @@ int woal_cfg80211_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev);
#if defined(WIFI_DIRECT_SUPPORT)
/** Define kernel version for wifi direct */
#if !defined(COMPAT_WIRELESS)
-#define WIFI_DIRECT_KERNEL_VERSION KERNEL_VERSION(3,0,0)
+#define WIFI_DIRECT_KERNEL_VERSION KERNEL_VERSION(2,6,39)
#else
#define WIFI_DIRECT_KERNEL_VERSION KERNEL_VERSION(2,6,33)
#endif /* COMPAT_WIRELESS */
@@ -173,7 +179,7 @@ int woal_cfg80211_init_p2p_go(moal_private * priv);
int woal_cfg80211_deinit_p2p(moal_private * priv);
-int woal_cfg80211_remain_on_channel_cfg(struct wiphy *wiphy,
+int woal_cfg80211_remain_on_channel_cfg(moal_private * priv,
t_u8 wait_option, t_u8 remove,
t_u8 * status,
struct ieee80211_channel *chan,
@@ -184,6 +190,8 @@ int woal_uap_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
#endif /* KERNEL_VERSION */
#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
+const t_u8 *woal_parse_ie_tlv(const t_u8 * ie, int len, t_u8 id);
+
int woal_cfg80211_mgmt_frame_ie(moal_private * priv,
const t_u8 * beacon_ies, size_t beacon_ies_len,
const t_u8 * proberesp_ies,
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.c b/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.c
index 2282216f7d55..31040a29ceec 100644
--- a/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.c
+++ b/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.c
@@ -50,10 +50,29 @@ Change log:
#define PRIV_CMD_BANDCFG "bandcfg"
/** Private command: Host cmd */
#define PRIV_CMD_HOSTCMD "hostcmd"
+/** Private command: Custom IE config*/
+#define PRIV_CMD_CUSTOMIE "customie"
/** Private command: HT Tx Cfg */
#define PRIV_CMD_HTTXCFG "httxcfg"
#define PRIV_CMD_DATARATE "getdatarate"
#define PRIV_CMD_TXRATECFG "txratecfg"
+#define PRIV_CMD_ESUPPMODE "esuppmode"
+#define PRIV_CMD_PASSPHRASE "passphrase"
+#define PRIV_CMD_DEAUTH "deauth"
+#if defined(WIFI_DIRECT_SUPPORT)
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+#define PRIV_CMD_BSSROLE "bssrole"
+#endif
+#endif
+#ifdef STA_SUPPORT
+#define PRIV_CMD_SETUSERSCAN "setuserscan"
+#endif
+#define PRIV_CMD_DEEPSLEEP "deepsleep"
+#define PRIV_CMD_IPADDR "ipaddr"
+#define PRIV_CMD_WPSSESSION "wpssession"
+#define PRIV_CMD_OTPUSERDATA "otpuserdata"
+#define PRIV_CMD_COUNTRYCODE "countrycode"
+#define PRIV_CMD_TCPACKENH "tcpackenh"
/** Bands supported in Infra mode */
static t_u8 SupportedInfraBand[] = {
@@ -76,6 +95,17 @@ static t_u8 SupportedAdhocBand[] = {
/********************************************************
Global Variables
********************************************************/
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
+#ifdef UAP_SUPPORT
+/** Network device handlers for uAP */
+extern const struct net_device_ops woal_uap_netdev_ops;
+#endif
+#ifdef STA_SUPPORT
+/** Network device handlers for STA */
+extern const struct net_device_ops woal_netdev_ops;
+#endif
+#endif
+extern int cfg80211_wext;
/********************************************************
Local Functions
@@ -85,7 +115,7 @@ static t_u8 SupportedAdhocBand[] = {
*
* @param pos Pointer to the arguments string
* @param data Pointer to the arguments buffer
- * @param len Pointer to the number of arguments extracted
+ * @param user_data_len Pointer to the number of arguments extracted
*
* @return MLAN_STATUS_SUCCESS
*
@@ -246,7 +276,6 @@ woal_get_priv_driver_version(moal_private * priv, t_u8 * respbuf,
return ret;
}
-#ifdef WIFI_DIRECT_SUPPORT
/**
* @brief Hostcmd interface from application
*
@@ -296,8 +325,12 @@ woal_priv_hostcmd(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen)
ret = -EFAULT;
goto error;
}
- sprintf(respbuf, "OK");
- ret = 3;
+ memcpy(data_ptr + sizeof(buf_len), misc_cfg->param.hostcmd.cmd,
+ misc_cfg->param.hostcmd.len);
+ ret =
+ misc_cfg->param.hostcmd.len + sizeof(buf_len) + strlen(CMD_MARVELL) +
+ strlen(PRIV_CMD_HOSTCMD);
+ memcpy(data_ptr, (t_u8 *) & ret, sizeof(t_u32));
error:
if (req)
@@ -306,7 +339,65 @@ woal_priv_hostcmd(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen)
LEAVE();
return ret;
}
-#endif
+
+/**
+ * @brief Custom IE setting
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int
+woal_priv_customie(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen)
+{
+ int ret = 0;
+ t_u8 *data_ptr;
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ds_misc_custom_ie *custom_ie = NULL;
+
+ ENTER();
+ data_ptr = respbuf + (strlen(CMD_MARVELL) + strlen(PRIV_CMD_CUSTOMIE));
+
+ custom_ie = (mlan_ds_misc_custom_ie *) data_ptr;
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ misc = (mlan_ds_misc_cfg *) ioctl_req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_CUSTOM_IE;
+ ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
+ if ((custom_ie->len == 0) ||
+ (custom_ie->len == sizeof(custom_ie->ie_data_list[0].ie_index)))
+ ioctl_req->action = MLAN_ACT_GET;
+ else
+ ioctl_req->action = MLAN_ACT_SET;
+
+ memcpy(&misc->param.cust_ie, custom_ie, sizeof(mlan_ds_misc_custom_ie));
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ custom_ie = (mlan_ds_misc_custom_ie *) data_ptr;
+ memcpy(custom_ie, &misc->param.cust_ie, sizeof(mlan_ds_misc_custom_ie));
+ ret = sizeof(mlan_ds_misc_custom_ie);
+ if (ioctl_req->status_code == MLAN_ERROR_IOCTL_FAIL) {
+ /* send a separate error code to indicate error from driver */
+ ret = EFAULT;
+ }
+ done:
+ if (ioctl_req) {
+ kfree(ioctl_req);
+ }
+ LEAVE();
+ return ret;
+}
/**
* @brief Set/Get Band and Adhoc-band setting
@@ -728,6 +819,824 @@ woal_setget_priv_txratecfg(moal_private * priv, t_u8 * respbuf,
}
/**
+ * @brief Set/Get esupplicant mode configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int
+woal_setget_priv_esuppmode(moal_private * priv, t_u8 * respbuf,
+ t_u32 respbuflen)
+{
+ t_u32 data[3];
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ woal_esuppmode_cfg *esupp_mode = NULL;
+ int ret = 0;
+ int user_data_len = 0;
+
+ ENTER();
+
+ if (strlen(respbuf) == (strlen(CMD_MARVELL) + strlen(PRIV_CMD_ESUPPMODE))) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ memset((char *) data, 0, sizeof(data));
+ parse_arguments(respbuf + strlen(CMD_MARVELL) +
+ strlen(PRIV_CMD_ESUPPMODE), data, &user_data_len);
+ }
+
+ if (user_data_len >= 4 || user_data_len == 1 || user_data_len == 2) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ESUPP_MODE;
+
+ if (user_data_len == 0) {
+ /* Get operation */
+ req->action = MLAN_ACT_GET;
+ } else {
+ /* Set operation */
+ req->action = MLAN_ACT_SET;
+ /* RSN mode */
+ sec->param.esupp_mode.rsn_mode = data[0];
+ /* Pairwise cipher */
+ sec->param.esupp_mode.act_paircipher = (data[1] & 0xFF);
+ /* Group cipher */
+ sec->param.esupp_mode.act_groupcipher = (data[2] & 0xFF);
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ esupp_mode = (woal_esuppmode_cfg *) respbuf;
+ esupp_mode->rsn_mode = (t_u16) ((sec->param.esupp_mode.rsn_mode) & 0xFFFF);
+ esupp_mode->pairwise_cipher =
+ (t_u8) ((sec->param.esupp_mode.act_paircipher) & 0xFF);
+ esupp_mode->group_cipher =
+ (t_u8) ((sec->param.esupp_mode.act_groupcipher) & 0xFF);
+
+ ret = sizeof(woal_esuppmode_cfg);
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+
+}
+
+/**
+ * @brief Set/Get esupplicant passphrase configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int
+woal_setget_priv_passphrase(moal_private * priv, t_u8 * respbuf,
+ t_u32 respbuflen)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ int ret = 0, action = -1, i = 0;
+ char *begin, *end, *opt;
+ t_u16 len = 0;
+ t_u8 zero_mac[] = { 0, 0, 0, 0, 0, 0 };
+ t_u8 *mac = NULL;
+
+ ENTER();
+
+ if (strlen(respbuf) == (strlen(CMD_MARVELL) + strlen(PRIV_CMD_PASSPHRASE))) {
+ PRINTM(MERROR, "No arguments provided\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* Parse the buf to get the cmd_action */
+ begin = respbuf + strlen(CMD_MARVELL) + strlen(PRIV_CMD_PASSPHRASE);
+ end = woal_strsep(&begin, ';', '/');
+ if (end)
+ action = woal_atox(end);
+ if (action < 0 || action > 2 || end[1] != '\0') {
+ PRINTM(MERROR, "Invalid action argument %s\n", end);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_PASSPHRASE;
+ if (action == 0)
+ req->action = MLAN_ACT_GET;
+ else
+ req->action = MLAN_ACT_SET;
+
+ while (begin) {
+ end = woal_strsep(&begin, ';', '/');
+ opt = woal_strsep(&end, '=', '/');
+ if (!opt || !end || !end[0]) {
+ PRINTM(MERROR, "Invalid option\n");
+ ret = -EINVAL;
+ break;
+ } else if (!strnicmp(opt, "ssid", strlen(opt))) {
+ if (strlen(end) > MLAN_MAX_SSID_LENGTH) {
+ PRINTM(MERROR, "SSID length exceeds max length\n");
+ ret = -EFAULT;
+ break;
+ }
+ sec->param.passphrase.ssid.ssid_len = strlen(end);
+ strncpy((char *) sec->param.passphrase.ssid.ssid, end, strlen(end));
+ PRINTM(MINFO, "ssid=%s, len=%d\n", sec->param.passphrase.ssid.ssid,
+ (int) sec->param.passphrase.ssid.ssid_len);
+ } else if (!strnicmp(opt, "bssid", strlen(opt))) {
+ woal_mac2u8((t_u8 *) & sec->param.passphrase.bssid, end);
+ } else if (!strnicmp(opt, "psk", strlen(opt)) &&
+ req->action == MLAN_ACT_SET) {
+ if (strlen(end) != MLAN_PMK_HEXSTR_LENGTH) {
+ PRINTM(MERROR, "Invalid PMK length\n");
+ ret = -EINVAL;
+ break;
+ }
+ woal_ascii2hex((t_u8 *) (sec->param.passphrase.psk.pmk.pmk), end,
+ MLAN_PMK_HEXSTR_LENGTH / 2);
+ sec->param.passphrase.psk_type = MLAN_PSK_PMK;
+ } else if (!strnicmp(opt, "passphrase", strlen(opt)) &&
+ req->action == MLAN_ACT_SET) {
+ if (strlen(end) < MLAN_MIN_PASSPHRASE_LENGTH ||
+ strlen(end) > MLAN_MAX_PASSPHRASE_LENGTH) {
+ PRINTM(MERROR, "Invalid length for passphrase\n");
+ ret = -EINVAL;
+ break;
+ }
+ sec->param.passphrase.psk_type = MLAN_PSK_PASSPHRASE;
+ strncpy(sec->param.passphrase.psk.passphrase.passphrase, end,
+ sizeof(sec->param.passphrase.psk.passphrase.passphrase));
+ sec->param.passphrase.psk.passphrase.passphrase_len = strlen(end);
+ PRINTM(MINFO, "passphrase=%s, len=%d\n",
+ sec->param.passphrase.psk.passphrase.passphrase,
+ (int) sec->param.passphrase.psk.passphrase.passphrase_len);
+ } else {
+ PRINTM(MERROR, "Invalid option %s\n", opt);
+ ret = -EINVAL;
+ break;
+ }
+ }
+ if (ret)
+ goto done;
+
+ if (action == 2)
+ sec->param.passphrase.psk_type = MLAN_PSK_CLEAR;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(respbuf, 0, respbuflen);
+ if (sec->param.passphrase.ssid.ssid_len) {
+ len += sprintf(respbuf + len, "ssid:");
+ memcpy(respbuf + len, sec->param.passphrase.ssid.ssid,
+ sec->param.passphrase.ssid.ssid_len);
+ len += sec->param.passphrase.ssid.ssid_len;
+ len += sprintf(respbuf + len, " ");
+ }
+ if (memcmp(&sec->param.passphrase.bssid, zero_mac, sizeof(zero_mac))) {
+ mac = (t_u8 *) & sec->param.passphrase.bssid;
+ len += sprintf(respbuf + len, "bssid:");
+ for (i = 0; i < ETH_ALEN - 1; ++i)
+ len += sprintf(respbuf + len, "%02x:", mac[i]);
+ len += sprintf(respbuf + len, "%02x ", mac[i]);
+ }
+ if (sec->param.passphrase.psk_type == MLAN_PSK_PMK) {
+ len += sprintf(respbuf + len, "psk:");
+ for (i = 0; i < MLAN_MAX_KEY_LENGTH; ++i)
+ len +=
+ sprintf(respbuf + len, "%02x",
+ sec->param.passphrase.psk.pmk.pmk[i]);
+ len += sprintf(respbuf + len, "\n");
+ }
+ if (sec->param.passphrase.psk_type == MLAN_PSK_PASSPHRASE) {
+ len +=
+ sprintf(respbuf + len, "passphrase:%s \n",
+ sec->param.passphrase.psk.passphrase.passphrase);
+ }
+
+ ret = len;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+
+}
+
+/**
+ * @brief Deauthenticate
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int
+woal_priv_deauth(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen)
+{
+ mlan_ioctl_req *req = NULL;
+ int ret = 0;
+ t_u8 mac[ETH_ALEN];
+
+ ENTER();
+
+ if (strlen(respbuf) > (strlen(CMD_MARVELL) + strlen(PRIV_CMD_DEAUTH))) {
+ /* Deauth mentioned BSSID */
+ woal_mac2u8(mac,
+ respbuf + strlen(CMD_MARVELL) + strlen(PRIV_CMD_DEAUTH));
+ if (MLAN_STATUS_SUCCESS != woal_disconnect(priv, MOAL_IOCTL_WAIT, mac)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ if (MLAN_STATUS_SUCCESS != woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL))
+ ret = -EFAULT;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+#if defined(WIFI_DIRECT_SUPPORT)
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+/**
+ * @brief Set/Get BSS role
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int
+woal_priv_bssrole(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen)
+{
+ t_u32 data[1];
+ int ret = 0;
+ int user_data_len = 0;
+ t_u8 action = MLAN_ACT_GET;
+
+ ENTER();
+
+ if (strlen(respbuf) == (strlen(CMD_MARVELL) + strlen(PRIV_CMD_BSSROLE))) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ memset((char *) data, 0, sizeof(data));
+ parse_arguments(respbuf + strlen(CMD_MARVELL) +
+ strlen(PRIV_CMD_BSSROLE), data, &user_data_len);
+ }
+
+ if (user_data_len >= 2) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if (user_data_len == 0) {
+ action = MLAN_ACT_GET;
+ } else {
+ if ((data[0] != MLAN_BSS_ROLE_STA &&
+ data[0] != MLAN_BSS_ROLE_UAP) ||
+ priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT) {
+ PRINTM(MWARN, "Invalid BSS role\n");
+ ret = -EINVAL;
+ goto error;
+ }
+ if (data[0] == GET_BSS_ROLE(priv)) {
+ PRINTM(MWARN, "Already BSS is in desired role\n");
+ goto done;
+ }
+ action = MLAN_ACT_SET;
+ /* Reset interface */
+ woal_reset_intf(priv, MOAL_IOCTL_WAIT, MFALSE);
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_bss_role_cfg(priv,
+ action, MOAL_IOCTL_WAIT,
+ (t_u8 *) data)) {
+ ret = -EFAULT;
+ goto error;
+ }
+
+ if (user_data_len) {
+ /* Initialize private structures */
+ woal_init_priv(priv, MOAL_IOCTL_WAIT);
+ /* Enable interfaces */
+ netif_device_attach(priv->netdev);
+ woal_start_queue(priv->netdev);
+ }
+
+ done:
+ memset(respbuf, 0, respbuflen);
+ respbuf[0] = (t_u8) data[0];
+ ret = 1;
+
+ error:
+ LEAVE();
+ return ret;
+}
+#endif /* STA_SUPPORT && UAP_SUPPORT */
+#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
+
+#ifdef STA_SUPPORT
+/**
+ * @brief Set user scan
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int
+woal_priv_setuserscan(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen)
+{
+ wlan_user_scan_cfg scan_cfg;
+ int ret = 0;
+
+ ENTER();
+
+ /* Create the scan_cfg structure */
+ memset(&scan_cfg, 0, sizeof(scan_cfg));
+
+ /* We expect the scan_cfg structure to be passed in respbuf */
+ memcpy((char *) &scan_cfg,
+ respbuf + strlen(CMD_MARVELL) + strlen(PRIV_CMD_SETUSERSCAN),
+ sizeof(wlan_user_scan_cfg));
+
+ /* Call for scan */
+ if (MLAN_STATUS_FAILURE == woal_do_scan(priv, &scan_cfg))
+ ret = -EFAULT;
+
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Set/Get deep sleep mode configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int
+woal_priv_setgetdeepsleep(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen)
+{
+ t_u32 data[2];
+ int ret = 0;
+ int user_data_len = 0;
+
+ ENTER();
+
+ if (strlen(respbuf) == (strlen(CMD_MARVELL) + strlen(PRIV_CMD_DEEPSLEEP))) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ memset((char *) data, 0, sizeof(data));
+ parse_arguments(respbuf + strlen(CMD_MARVELL) +
+ strlen(PRIV_CMD_DEEPSLEEP), data, &user_data_len);
+ }
+
+ if (user_data_len >= 3) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (user_data_len == 0) {
+ if (MLAN_STATUS_SUCCESS != woal_get_deep_sleep(priv, data)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ sprintf(respbuf, "%d %d", data[0], data[1]);
+ ret = strlen(respbuf) + 1;
+ } else {
+ if (data[0] == DEEP_SLEEP_OFF) {
+ PRINTM(MINFO, "Exit Deep Sleep Mode\n");
+ ret = woal_set_deep_sleep(priv, MOAL_IOCTL_WAIT, MFALSE, 0);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ ret = -EINVAL;
+ goto done;
+ }
+ } else if (data[0] == DEEP_SLEEP_ON) {
+ PRINTM(MINFO, "Enter Deep Sleep Mode\n");
+ if (user_data_len != 2)
+ data[1] = 0;
+ ret = woal_set_deep_sleep(priv, MOAL_IOCTL_WAIT, MTRUE, data[1]);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ ret = -EINVAL;
+ goto done;
+ }
+ } else {
+ PRINTM(MERROR, "Unknown option = %u\n", data[0]);
+ ret = -EINVAL;
+ goto done;
+ }
+ ret = sprintf(respbuf, "OK\n") + 1;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+
+}
+
+/**
+ * @brief Set/Get IP address configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int
+woal_priv_setgetipaddr(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ int ret = 0, op_code = 0, data_length = 0, header = 0;
+
+ ENTER();
+
+ header = strlen(CMD_MARVELL) + strlen(PRIV_CMD_IPADDR);
+ data_length = strlen(respbuf) - header;
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+
+ if (data_length < 1) { /* GET */
+ req->action = MLAN_ACT_GET;
+ } else {
+ /* Make sure we have the operation argument */
+ if (data_length > 2 && respbuf[header + 1] != ';') {
+ PRINTM(MERROR, "No operation argument. Separate with ';'\n");
+ ret = -EINVAL;
+ goto done;
+ } else {
+ respbuf[header + 1] = '\0';
+ }
+ req->action = MLAN_ACT_SET;
+
+ /* Only one IP is supported in current firmware */
+ memset(misc->param.ipaddr_cfg.ip_addr[0], 0, IPADDR_LEN);
+ in4_pton(&respbuf[header + 2],
+ MIN((IPADDR_MAX_BUF - 3), (data_length - 2)),
+ misc->param.ipaddr_cfg.ip_addr[0], ' ', NULL);
+ misc->param.ipaddr_cfg.ip_addr_num = 1;
+ misc->param.ipaddr_cfg.ip_addr_type = IPADDR_TYPE_IPV4;
+
+ if (woal_atoi(&op_code, &respbuf[header]) != MLAN_STATUS_SUCCESS) {
+ ret = -EINVAL;
+ goto done;
+ }
+ misc->param.ipaddr_cfg.op_code = (t_u32) op_code;
+ }
+
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ misc->sub_command = MLAN_OID_MISC_IP_ADDR;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (req->action == MLAN_ACT_GET) {
+ snprintf(respbuf, IPADDR_MAX_BUF, "%d;%d.%d.%d.%d",
+ misc->param.ipaddr_cfg.op_code,
+ misc->param.ipaddr_cfg.ip_addr[0][0],
+ misc->param.ipaddr_cfg.ip_addr[0][1],
+ misc->param.ipaddr_cfg.ip_addr[0][2],
+ misc->param.ipaddr_cfg.ip_addr[0][3]);
+ ret = IPADDR_MAX_BUF + 1;
+ } else {
+ ret = sprintf(respbuf, "OK\n") + 1;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get WPS session configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int
+woal_priv_setwpssession(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_wps_cfg *pwps = NULL;
+ t_u32 data[1];
+ int ret = 0;
+ int user_data_len = 0;
+
+ ENTER();
+
+ if (strlen(respbuf) == (strlen(CMD_MARVELL) + strlen(PRIV_CMD_WPSSESSION))) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ memset((char *) data, 0, sizeof(data));
+ parse_arguments(respbuf + strlen(CMD_MARVELL) +
+ strlen(PRIV_CMD_WPSSESSION), data, &user_data_len);
+ }
+
+ if (user_data_len != 1) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wps_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ pwps = (mlan_ds_wps_cfg *) req->pbuf;
+
+ req->req_id = MLAN_IOCTL_WPS_CFG;
+ req->action = MLAN_ACT_SET;
+ pwps->sub_command = MLAN_OID_WPS_CFG_SESSION;
+
+ if (data[0] == 1)
+ pwps->param.wps_session = MLAN_WPS_CFG_SESSION_START;
+ else
+ pwps->param.wps_session = MLAN_WPS_CFG_SESSION_END;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ ret = sprintf(respbuf, "OK\n") + 1;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get OTP user data
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int
+woal_priv_otpuserdata(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen)
+{
+ int data[1];
+ int user_data_len = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ds_misc_otp_user_data *otp = NULL;
+ int ret = 0;
+
+ ENTER();
+
+ memset((char *) data, 0, sizeof(data));
+ parse_arguments(respbuf + strlen(CMD_MARVELL) +
+ strlen(PRIV_CMD_OTPUSERDATA), data, &user_data_len);
+
+ if (user_data_len > 1) {
+ PRINTM(MERROR, "Too many arguments\n");
+ LEAVE();
+ return -EINVAL;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ req->action = MLAN_ACT_GET;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_OTP_USER_DATA;
+ misc->param.otp_user_data.user_data_length = data[0];
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ otp = (mlan_ds_misc_otp_user_data *) req->pbuf;
+
+ if (req->action == MLAN_ACT_GET) {
+ ret = MIN(otp->user_data_length, data[0]);
+ memcpy(respbuf, otp->user_data, ret);
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set / Get country code
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int
+woal_priv_set_get_countrycode(moal_private * priv, t_u8 * respbuf,
+ t_u32 respbuflen)
+{
+ int ret = 0;
+ // char data[COUNTRY_CODE_LEN] = {0, 0, 0};
+ int header = 0, data_length = 0; // wrq->u.data.length;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *pcfg_misc = NULL;
+ mlan_ds_misc_country_code *country_code = NULL;
+
+ ENTER();
+
+ header = strlen(CMD_MARVELL) + strlen(PRIV_CMD_COUNTRYCODE);
+ data_length = strlen(respbuf) - header;
+
+ if (data_length > COUNTRY_CODE_LEN) {
+ PRINTM(MERROR, "Invalid argument!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ pcfg_misc = (mlan_ds_misc_cfg *) req->pbuf;
+ country_code = &pcfg_misc->param.country_code;
+ pcfg_misc->sub_command = MLAN_OID_MISC_COUNTRY_CODE;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ if (data_length <= 1) {
+ req->action = MLAN_ACT_GET;
+ } else {
+ memset(country_code->country_code, 0, COUNTRY_CODE_LEN);
+ memcpy(country_code->country_code, respbuf + header, COUNTRY_CODE_LEN);
+ req->action = MLAN_ACT_SET;
+ }
+
+ /* Send IOCTL request to MLAN */
+ if (woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT) != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (req->action == MLAN_ACT_GET) {
+ ret = data_length = COUNTRY_CODE_LEN;
+ memset(respbuf + header, 0, COUNTRY_CODE_LEN);
+ memcpy(respbuf, country_code->country_code, COUNTRY_CODE_LEN);
+ }
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get TCP Ack enhancement configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int
+woal_priv_setgettcpackenh(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen)
+{
+ t_u32 data[1];
+ int ret = 0;
+ int user_data_len = 0;
+ struct list_head *link = NULL;
+ struct tcp_sess *tcp_sess = NULL;
+
+ ENTER();
+
+ if (strlen(respbuf) == (strlen(CMD_MARVELL) + strlen(PRIV_CMD_TCPACKENH))) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ memset((char *) data, 0, sizeof(data));
+ parse_arguments(respbuf + strlen(CMD_MARVELL) +
+ strlen(PRIV_CMD_TCPACKENH), data, &user_data_len);
+ }
+
+ if (user_data_len >= 2) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (user_data_len == 0) {
+ /* get operation */
+ respbuf[0] = priv->enable_tcp_ack_enh;
+ } else {
+ /* set operation */
+ if (data[0] == MTRUE) {
+ PRINTM(MINFO, "Enabling TCP Ack enhancement\n");
+ priv->enable_tcp_ack_enh = MTRUE;
+ } else if (data[0] == MFALSE) {
+ PRINTM(MINFO, "Disabling TCP Ack enhancement\n");
+ priv->enable_tcp_ack_enh = MFALSE;
+ /* release the tcp sessions if any */
+ while (!list_empty(&priv->tcp_sess_queue)) {
+ link = priv->tcp_sess_queue.next;
+ tcp_sess = list_entry(link, struct tcp_sess, link);
+ PRINTM(MINFO,
+ "Disable TCP ACK Enh: release a tcp session in dl. (src: ipaddr 0x%08x, port: %d. dst: ipaddr 0x%08x, port: %d\n",
+ tcp_sess->src_ip_addr, tcp_sess->src_tcp_port,
+ tcp_sess->dst_ip_addr, tcp_sess->dst_tcp_port);
+ list_del(link);
+ kfree(tcp_sess);
+ }
+ } else {
+ PRINTM(MERROR, "Unknown option = %u\n", data[0]);
+ ret = -EINVAL;
+ goto done;
+ }
+ respbuf[0] = priv->enable_tcp_ack_enh;
+ }
+ ret = 1;
+
+ done:
+ LEAVE();
+ return ret;
+
+}
+
+/**
* @brief Set priv command for Android
* @param dev A pointer to net_device structure
* @param req A pointer to ifreq structure
@@ -788,7 +1697,6 @@ woal_android_priv_cmd(struct net_device *dev, struct ifreq *req)
/* Set/Get band configuration */
len = woal_setget_priv_bandcfg(priv, buf, priv_cmd.total_len);
goto handled;
-#ifdef WIFI_DIRECT_SUPPORT
} else
if (strnicmp
(buf + strlen(CMD_MARVELL), PRIV_CMD_HOSTCMD,
@@ -796,7 +1704,6 @@ woal_android_priv_cmd(struct net_device *dev, struct ifreq *req)
/* hostcmd configuration */
len = woal_priv_hostcmd(priv, buf, priv_cmd.total_len);
goto handled;
-#endif
} else
if (strnicmp
(buf + strlen(CMD_MARVELL), PRIV_CMD_HTTXCFG,
@@ -818,13 +1725,110 @@ woal_android_priv_cmd(struct net_device *dev, struct ifreq *req)
/* Set/Get tx rate cfg */
len = woal_setget_priv_txratecfg(priv, buf, priv_cmd.total_len);
goto handled;
+ } else
+ if (strnicmp
+ (buf + strlen(CMD_MARVELL), PRIV_CMD_CUSTOMIE,
+ strlen(PRIV_CMD_CUSTOMIE)) == 0) {
+ /* Custom IE configuration */
+ len = woal_priv_customie(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else
+ if (strnicmp
+ (buf + strlen(CMD_MARVELL), PRIV_CMD_ESUPPMODE,
+ strlen(PRIV_CMD_ESUPPMODE)) == 0) {
+ /* Esupplicant mode configuration */
+ len = woal_setget_priv_esuppmode(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else
+ if (strnicmp
+ (buf + strlen(CMD_MARVELL), PRIV_CMD_PASSPHRASE,
+ strlen(PRIV_CMD_PASSPHRASE)) == 0) {
+ /* Esupplicant passphrase configuration */
+ len = woal_setget_priv_passphrase(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else
+ if (strnicmp
+ (buf + strlen(CMD_MARVELL), PRIV_CMD_DEAUTH,
+ strlen(PRIV_CMD_DEAUTH)) == 0) {
+ /* Deauth */
+ len = woal_priv_deauth(priv, buf, priv_cmd.total_len);
+ goto handled;
+#if defined(WIFI_DIRECT_SUPPORT)
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ } else
+ if (strnicmp
+ (buf + strlen(CMD_MARVELL), PRIV_CMD_BSSROLE,
+ strlen(PRIV_CMD_BSSROLE)) == 0) {
+ /* BSS Role */
+ len = woal_priv_bssrole(priv, buf, priv_cmd.total_len);
+ goto handled;
+#endif
+#endif
+#ifdef STA_SUPPORT
+ } else
+ if (strnicmp
+ (buf + strlen(CMD_MARVELL), PRIV_CMD_SETUSERSCAN,
+ strlen(PRIV_CMD_SETUSERSCAN)) == 0) {
+ /* Set user scan */
+ len = woal_priv_setuserscan(priv, buf, priv_cmd.total_len);
+ goto handled;
+#endif
+ } else
+ if (strnicmp
+ (buf + strlen(CMD_MARVELL), PRIV_CMD_DEEPSLEEP,
+ strlen(PRIV_CMD_DEEPSLEEP)) == 0) {
+ /* Deep sleep */
+ len = woal_priv_setgetdeepsleep(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else
+ if (strnicmp
+ (buf + strlen(CMD_MARVELL), PRIV_CMD_IPADDR,
+ strlen(PRIV_CMD_IPADDR)) == 0) {
+ /* IP address */
+ len = woal_priv_setgetipaddr(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else
+ if (strnicmp
+ (buf + strlen(CMD_MARVELL), PRIV_CMD_WPSSESSION,
+ strlen(PRIV_CMD_WPSSESSION)) == 0) {
+ /* WPS Session */
+ len = woal_priv_setwpssession(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else
+ if (strnicmp
+ (buf + strlen(CMD_MARVELL), PRIV_CMD_OTPUSERDATA,
+ strlen(PRIV_CMD_OTPUSERDATA)) == 0) {
+ /* OTP user data */
+ len = woal_priv_otpuserdata(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else
+ if (strnicmp
+ (buf + strlen(CMD_MARVELL), PRIV_CMD_COUNTRYCODE,
+ strlen(PRIV_CMD_COUNTRYCODE)) == 0) {
+ /* OTP user data */
+ len = woal_priv_set_get_countrycode(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else
+ if (strnicmp
+ (buf + strlen(CMD_MARVELL), PRIV_CMD_TCPACKENH,
+ strlen(PRIV_CMD_TCPACKENH)) == 0) {
+ /* OTP user data */
+ len = woal_priv_setgettcpackenh(priv, buf, priv_cmd.total_len);
+ goto handled;
} else {
/* Fall through, after stripping off the custom header */
buf += strlen(CMD_MARVELL);
}
}
#ifdef STA_SUPPORT
- if (strncmp(buf, "RSSI", strlen("RSSI")) == 0) {
+ if (strncmp(buf, "RSSILOW-THRESHOLD", strlen("RSSILOW-THRESHOLD")) == 0) {
+ pdata = buf + strlen("RSSILOW-THRESHOLD") + 1;
+ if (MLAN_STATUS_SUCCESS != woal_set_rssi_low_threshold(priv, pdata)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "RSSI", strlen("RSSI")) == 0) {
if (MLAN_STATUS_SUCCESS != woal_get_bss_info(priv,
MOAL_IOCTL_WAIT,
&bss_info)) {
@@ -983,12 +1987,14 @@ woal_android_priv_cmd(struct net_device *dev, struct ifreq *req)
priv->bg_scan_reported = MFALSE;
len = sprintf(buf, "OK\n") + 1;
} else if (strncmp(buf, "BGSCAN-STOP", strlen("BGSCAN-STOP")) == 0) {
- if (MLAN_STATUS_SUCCESS != woal_stop_bg_scan(priv)) {
- ret = -EFAULT;
- goto done;
+ if (priv->bg_scan_start && !priv->scan_cfg.rssi_threshold) {
+ if (MLAN_STATUS_SUCCESS != woal_stop_bg_scan(priv)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ priv->bg_scan_start = MFALSE;
+ priv->bg_scan_reported = MFALSE;
}
- priv->bg_scan_start = MFALSE;
- priv->bg_scan_reported = MFALSE;
len = sprintf(buf, "OK\n") + 1;
} else if (strncmp(buf, "RXFILTER-START", strlen("RXFILTER-START")) == 0) {
#ifdef MEF_CFG_RX_FILTER
@@ -1004,7 +2010,19 @@ woal_android_priv_cmd(struct net_device *dev, struct ifreq *req)
}
#endif
len = sprintf(buf, "OK\n") + 1;
- } else if (strncmp(buf, "RXFILTER-ADD", strlen("RXFILTER-ADD")) == 0) {
+ }
+#ifdef STA_CFG80211
+ else if (strncmp(buf, "GET_RSSI_STATUS", strlen("GET_RSSI_STATUS")) == 0) {
+ if (priv->rssi_status == MLAN_EVENT_ID_FW_BCN_RSSI_LOW)
+ len = sprintf(buf, "EVENT=BEACON_RSSI_LOW\n");
+ else if (priv->rssi_status == MLAN_EVENT_ID_FW_PRE_BCN_LOST)
+ len = sprintf(buf, "EVENT=PRE_BEACON_LOST\n");
+ else
+ len = sprintf(buf, "OK\n") + 1;
+ priv->rssi_status = 0;
+ }
+#endif
+ else if (strncmp(buf, "RXFILTER-ADD", strlen("RXFILTER-ADD")) == 0) {
pdata = buf + strlen("RXFILTER-ADD") + 1;
if (MLAN_STATUS_SUCCESS != woal_add_rxfilter(priv, pdata)) {
ret = -EFAULT;
@@ -1071,10 +2089,20 @@ woal_android_priv_cmd(struct net_device *dev, struct ifreq *req)
if (len > 0) {
priv_cmd.used_len = len;
- if (copy_to_user(priv_cmd.buf, buf, len)) {
+ if (priv_cmd.used_len < priv_cmd.total_len)
+ memset(priv_cmd.buf + priv_cmd.used_len, 0,
+ priv_cmd.total_len - priv_cmd.used_len);
+ if (copy_to_user(priv_cmd.buf, buf, priv_cmd.used_len)) {
PRINTM(MERROR, "%s: failed to copy data to user buffer\n",
__FUNCTION__);
ret = -EFAULT;
+ goto done;
+ }
+ if (copy_to_user
+ (req->ifr_data, &priv_cmd, sizeof(android_wifi_priv_cmd))) {
+ PRINTM(MERROR, "%s: failed to copy command header to user buffer\n",
+ __FUNCTION__);
+ ret = -EFAULT;
}
} else {
ret = len;
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.h b/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.h
index a1481e88ff21..a68991694a9d 100644
--- a/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.h
+++ b/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.h
@@ -44,12 +44,23 @@ Change log:
/** Private command ID to get BSS type */
#define WOAL_GET_BSS_TYPE (SIOCDEVPRIVATE + 15)
-int woal_do_ioctl(struct net_device *dev, struct ifreq *req, int i);
+int woal_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd);
+/*
+ * For android private commands, fixed value of ioctl is used.
+ * Internally commands are differentiated using strings.
+ *
+ * application needs to specify "total_len" of data for copy_from_user
+ * kernel updates "used_len" during copy_to_user
+ */
+/** Private command structure from app */
typedef struct _android_wifi_priv_cmd
{
+ /** Buffer pointer */
char *buf;
+ /** buffer updated by driver */
int used_len;
+ /** buffer sent by application */
int total_len;
} android_wifi_priv_cmd;
@@ -62,6 +73,16 @@ typedef struct woal_priv_tx_rate_cfg
t_u32 rate_index;
} woal_tx_rate_cfg;
+typedef struct woal_priv_esuppmode_cfg
+{
+ /* RSN mode */
+ t_u16 rsn_mode;
+ /* Pairwise cipher */
+ t_u8 pairwise_cipher;
+ /* Group cipher */
+ t_u8 group_cipher;
+} woal_esuppmode_cfg;
+
mlan_status woal_set_ap_wps_p2p_ie(moal_private * priv, t_u8 * ie, size_t len);
int woal_android_priv_cmd(struct net_device *dev, struct ifreq *req);
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_ioctl.c b/drivers/net/wireless/sd8797/mlinux/moal_ioctl.c
index efe6e7ddcea1..94fe7e11669e 100644
--- a/drivers/net/wireless/sd8797/mlinux/moal_ioctl.c
+++ b/drivers/net/wireless/sd8797/mlinux/moal_ioctl.c
@@ -2,7 +2,7 @@
*
* @brief This file contains ioctl function to MLAN
*
- * Copyright (C) 2008-2011, Marvell International Ltd.
+ * Copyright (C) 2008-2012, Marvell International Ltd.
*
* This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
@@ -792,7 +792,7 @@ woal_set_get_retry(moal_private * priv, t_u32 action,
#ifdef STA_CFG80211
/* If set is invoked from other than iw i.e iwconfig, wiphy retry count
should be updated as well */
- if (IS_STA_CFG80211(cfg80211_wext) &&
+ if (IS_STA_CFG80211(cfg80211_wext) && priv->wdev && priv->wdev->wiphy &&
(GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) && (action == MLAN_ACT_SET)) {
priv->wdev->wiphy->retry_long = (t_u8) * value;
priv->wdev->wiphy->retry_short = (t_u8) * value;
@@ -854,7 +854,7 @@ woal_set_get_rts(moal_private * priv, t_u32 action,
#ifdef STA_CFG80211
/* If set is invoked from other than iw i.e iwconfig, wiphy RTS threshold
should be updated as well */
- if (IS_STA_CFG80211(cfg80211_wext) &&
+ if (IS_STA_CFG80211(cfg80211_wext) && priv->wdev && priv->wdev->wiphy &&
(GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) && (action == MLAN_ACT_SET))
priv->wdev->wiphy->rts_threshold = *value;
#endif
@@ -914,7 +914,7 @@ woal_set_get_frag(moal_private * priv, t_u32 action,
#ifdef STA_CFG80211
/* If set is invoked from other than iw i.e iwconfig, wiphy fragment
threshold should be updated as well */
- if (IS_STA_CFG80211(cfg80211_wext) &&
+ if (IS_STA_CFG80211(cfg80211_wext) && priv->wdev && priv->wdev->wiphy &&
(GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) && (action == MLAN_ACT_SET))
priv->wdev->wiphy->frag_threshold = *value;
#endif
@@ -1096,7 +1096,7 @@ woal_set_get_power_mgmt(moal_private * priv,
#ifdef STA_CFG80211
/* If set is invoked from other than iw i.e iwconfig, wiphy IEEE power save
mode should be updated */
- if (IS_STA_CFG80211(cfg80211_wext) &&
+ if (IS_STA_CFG80211(cfg80211_wext) && priv->wdev &&
(GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) && (action == MLAN_ACT_SET)) {
if (*disabled)
priv->wdev->ps = MFALSE;
@@ -1780,20 +1780,22 @@ woal_get_bss_type(struct net_device *dev, struct ifreq *req)
#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
#if defined(STA_WEXT) || defined(UAP_WEXT)
/**
- * @brief Set/Get BSS role
+ * @brief Swithces BSS role of WFD interface
*
- * @param priv A pointer to moal_private structure
- * @param wrq A pointer to iwreq structure
+ * @param priv A pointer to moal_private structure
+ * @param action Action: set or get
+ * @param wait_option Wait option (MOAL_WAIT or MOAL_NO_WAIT)
+ * @param bss_role A pointer to bss role
*
* @return 0 --success, otherwise fail
*/
-int
-woal_set_get_bss_role(moal_private * priv, struct iwreq *wrq)
+mlan_status
+woal_bss_role_cfg(moal_private * priv, t_u8 action,
+ t_u8 wait_option, t_u8 * bss_role)
{
int ret = 0;
mlan_ds_bss *bss = NULL;
mlan_ioctl_req *req = NULL;
- int bss_role = 0;
struct net_device *dev = priv->netdev;
ENTER();
@@ -1812,55 +1814,26 @@ woal_set_get_bss_role(moal_private * priv, struct iwreq *wrq)
bss = (mlan_ds_bss *) req->pbuf;
bss->sub_command = MLAN_OID_BSS_ROLE;
req->req_id = MLAN_IOCTL_BSS;
- if (wrq->u.data.length) {
- if (copy_from_user(&bss_role, wrq->u.data.pointer, sizeof(int))) {
- PRINTM(MERROR, "Copy from user failed\n");
- ret = -EFAULT;
- goto done;
- }
- if (bss_role != MLAN_BSS_ROLE_STA && bss_role != MLAN_BSS_ROLE_UAP) {
- PRINTM(MWARN, "Invalid BSS role\n");
- ret = -EINVAL;
- goto done;
- }
- if (bss_role == GET_BSS_ROLE(priv)) {
- PRINTM(MWARN, "Already BSS is in desired role\n");
- ret = -EINVAL;
- goto done;
- }
- req->action = MLAN_ACT_SET;
- bss->param.bss_role = (t_u8) bss_role;
- } else {
- req->action = MLAN_ACT_GET;
- }
-
- if (req->action == MLAN_ACT_SET) {
- /* Reset interface */
- woal_reset_intf(priv, MOAL_IOCTL_WAIT, MFALSE);
+ req->action = action;
+ if (action == MLAN_ACT_SET) {
+ bss->param.bss_role = *bss_role;
}
- if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, wait_option)) {
ret = -EFAULT;
goto done;
}
- if (!wrq->u.data.length) {
- bss_role = (int) bss->param.bss_role;
- if (copy_to_user(wrq->u.data.pointer, &bss_role, sizeof(int))) {
- ret = -EFAULT;
- goto done;
- }
- wrq->u.data.length = 1;
+
+ if (action == MLAN_ACT_GET) {
+ *bss_role = bss->param.bss_role;
} else {
/* Update moal_private */
- priv->bss_role = bss_role;
+ priv->bss_role = *bss_role;
if (priv->bss_type == MLAN_BSS_TYPE_UAP)
priv->bss_type = MLAN_BSS_TYPE_STA;
else if (priv->bss_type == MLAN_BSS_TYPE_STA)
priv->bss_type = MLAN_BSS_TYPE_UAP;
- /* Initialize private structures */
- woal_init_priv(priv, MOAL_IOCTL_WAIT);
-
- if (bss_role == MLAN_BSS_ROLE_UAP) {
+ if (*bss_role == MLAN_BSS_ROLE_UAP) {
/* Switch: STA -> uAP */
/* Setup the OS Interface to our functions */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
@@ -1881,7 +1854,7 @@ woal_set_get_bss_role(moal_private * priv, struct iwreq *wrq)
init_waitqueue_head(&priv->w_stats_wait_q);
}
#endif /* UAP_WEXT */
- } else if (bss_role == MLAN_BSS_ROLE_STA) {
+ } else if (*bss_role == MLAN_BSS_ROLE_STA) {
/* Switch: uAP -> STA */
/* Setup the OS Interface to our functions */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
@@ -1903,9 +1876,6 @@ woal_set_get_bss_role(moal_private * priv, struct iwreq *wrq)
}
#endif /* STA_WEXT */
}
- /* Enable interfaces */
- netif_device_attach(dev);
- woal_start_queue(dev);
}
done:
@@ -1914,8 +1884,75 @@ woal_set_get_bss_role(moal_private * priv, struct iwreq *wrq)
LEAVE();
return ret;
}
-#endif
-#endif
+
+/**
+ * @brief Set/Get BSS role
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_set_get_bss_role(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ int bss_role = 0;
+ t_u8 action = MLAN_ACT_GET;
+
+ ENTER();
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&bss_role, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if ((bss_role != MLAN_BSS_ROLE_STA &&
+ bss_role != MLAN_BSS_ROLE_UAP) ||
+ (priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT)) {
+ PRINTM(MWARN, "Invalid BSS role\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (bss_role == GET_BSS_ROLE(priv)) {
+ PRINTM(MWARN, "Already BSS is in desired role\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ action = MLAN_ACT_SET;
+ /* Reset interface */
+ woal_reset_intf(priv, MOAL_IOCTL_WAIT, MFALSE);
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_bss_role_cfg(priv,
+ action, MOAL_IOCTL_WAIT,
+ (t_u8 *) & bss_role)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (!wrq->u.data.length) {
+ if (copy_to_user(wrq->u.data.pointer, &bss_role, sizeof(int))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ } else {
+ /* Initialize private structures */
+ woal_init_priv(priv, MOAL_IOCTL_WAIT);
+
+ /* Enable interfaces */
+ netif_device_attach(priv->netdev);
+ woal_start_queue(priv->netdev);
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+#endif /* STA_WEXT || UAP_WEXT */
+#endif /* STA_SUPPORT && UAP_SUPPORT */
#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
/**
@@ -1993,6 +2030,7 @@ woal_cancel_hs(moal_private * priv, t_u8 wait_option)
return ret;
}
+#if defined(SDIO_SUSPEND_RESUME)
/** @brief This function enables the host sleep
*
* @param priv A Pointer to the moal_private structure
@@ -2074,6 +2112,7 @@ woal_enable_hs(moal_private * priv)
LEAVE();
return hs_actived;
}
+#endif
/**
* @brief This function send soft_reset command to firmware
@@ -2525,6 +2564,48 @@ woal_get_pm_info(moal_private * priv, mlan_ds_ps_info * pm_info)
}
/**
+ * @brief Get Deep Sleep
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param data Pointer to return deep_sleep setting
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_get_deep_sleep(moal_private * priv, t_u32 * data)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_pm_cfg *pm = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ pm = (mlan_ds_pm_cfg *) req->pbuf;
+ pm->sub_command = MLAN_OID_PM_CFG_DEEP_SLEEP;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ *data = pm->param.auto_deep_sleep.auto_ds;
+ *(data + 1) = pm->param.auto_deep_sleep.idletime;
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
* @brief Set Deep Sleep
*
* @param priv Pointer to the moal_private driver data struct
@@ -2665,8 +2746,7 @@ woal_11h_channel_check_ioctl(moal_private * priv)
* @return MLAN_STATUS_SUCCESS -- success, otherwise fail
*/
mlan_status
-woal_cfg80211_wifi_direct_mode_cfg(moal_private * priv, t_u16 action,
- t_u16 * mode)
+woal_wifi_direct_mode_cfg(moal_private * priv, t_u16 action, t_u16 * mode)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_ioctl_req *req = NULL;
@@ -3640,6 +3720,13 @@ woal_set_bg_scan(moal_private * priv, char *buf, int length)
ptr += 2;
buf_left -= 2;
break;
+ case WEXT_BGSCAN_REPEAT_SECTION:
+ priv->scan_cfg.repeat_count = (t_u16) ptr[1];
+ PRINTM(MIOCTL, "BG scan: repeat_count=%d\n",
+ (int) priv->scan_cfg.repeat_count);
+ ptr += 2;
+ buf_left -= 2;
+ break;
case WEXT_BGSCAN_INTERVAL_SECTION:
priv->scan_cfg.scan_interval = (ptr[2] << 8 | ptr[1]) * 1000;
PRINTM(MIOCTL, "BG scan: scan_interval=%d\n",
@@ -3728,7 +3815,7 @@ woal_reconfig_bgscan(moal_handle * handle)
* @brief set rssi low threshold
*
* @param priv A pointer to moal_private structure
- * @param scan_type MLAN_SCAN_TYPE_ACTIVE/MLAN_SCAN_TYPE_PASSIVE
+ * @param rssi A pointer to low rssi
*
* @return MLAN_STATUS_SUCCESS -- success, otherwise fail
*/
@@ -3754,10 +3841,16 @@ woal_set_rssi_low_threshold(moal_private * priv, char *rssi)
misc->sub_command = MLAN_OID_MISC_SUBSCRIBE_EVENT;
req->action = MLAN_ACT_SET;
misc->param.subscribe_event.evt_bitmap = SUBSCRIBE_EVT_RSSI_LOW;
+ misc->param.subscribe_event.evt_bitmap |= SUBSCRIBE_EVT_PRE_BEACON_LOST;
+ misc->param.subscribe_event.pre_beacon_miss = DEFAULT_PRE_BEACON_MISS;
+
if (MLAN_STATUS_SUCCESS != woal_atoi(&low_rssi, rssi)) {
ret = -EFAULT;
goto done;
}
+#ifdef STA_CFG80211
+ priv->mrvl_rssi_low = low_rssi;
+#endif
misc->param.subscribe_event.low_rssi = low_rssi;
misc->param.subscribe_event.low_rssi_freq = 0;
if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
@@ -3771,6 +3864,69 @@ woal_set_rssi_low_threshold(moal_private * priv, char *rssi)
return ret;
}
+#ifdef STA_CFG80211
+/**
+ * @brief set rssi low threshold
+ *
+ * @param priv A pointer to moal_private structure
+ * @param event_id event id.
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_set_rssi_threshold(moal_private * priv, t_u32 event_id)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+
+ ENTER();
+ if (priv->media_connected == MFALSE)
+ goto done;
+ if (priv->mrvl_rssi_low)
+ goto done;
+ if (event_id == MLAN_EVENT_ID_FW_BCN_RSSI_LOW) {
+ if (priv->last_rssi_low < 100)
+ priv->last_rssi_low += priv->cqm_rssi_hyst;
+ priv->last_rssi_high = abs(priv->cqm_rssi_thold);
+ } else if (event_id == MLAN_EVENT_ID_FW_BCN_RSSI_HIGH) {
+ priv->last_rssi_low = abs(priv->cqm_rssi_thold);
+ if (priv->last_rssi_high > priv->cqm_rssi_hyst)
+ priv->last_rssi_high -= priv->cqm_rssi_hyst;
+ } else {
+ priv->last_rssi_low = abs(priv->cqm_rssi_thold);
+ priv->last_rssi_high = abs(priv->cqm_rssi_thold);
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ misc->sub_command = MLAN_OID_MISC_SUBSCRIBE_EVENT;
+ req->action = MLAN_ACT_SET;
+ misc->param.subscribe_event.evt_bitmap =
+ SUBSCRIBE_EVT_RSSI_LOW | SUBSCRIBE_EVT_RSSI_HIGH;
+ misc->param.subscribe_event.low_rssi_freq = 0;
+ misc->param.subscribe_event.low_rssi = priv->last_rssi_low;
+ misc->param.subscribe_event.high_rssi_freq = 0;
+ misc->param.subscribe_event.high_rssi = priv->last_rssi_high;
+ PRINTM(MIOCTL, "rssi_low=%d, rssi_high=%d\n", (int) priv->last_rssi_low,
+ (int) priv->last_rssi_high);
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+#endif
+
/**
* @brief Get power mode
*
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_main.c b/drivers/net/wireless/sd8797/mlinux/moal_main.c
index eac248b70129..d5bed42fa73d 100644
--- a/drivers/net/wireless/sd8797/mlinux/moal_main.c
+++ b/drivers/net/wireless/sd8797/mlinux/moal_main.c
@@ -47,6 +47,11 @@ Change log:
#include <linux/wlan_plat.h>
#include "moal_eth_ioctl.h"
+#include <linux/if_ether.h>
+#include <linux/in.h>
+#include <linux/tcp.h>
+#include <net/tcp.h>
+
/********************************************************
Local Variables
********************************************************/
@@ -205,7 +210,7 @@ int woal_close(struct net_device *dev);
int woal_set_mac_address(struct net_device *dev, void *addr);
void woal_tx_timeout(struct net_device *dev);
struct net_device_stats *woal_get_stats(struct net_device *dev);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
u16 woal_select_queue(struct net_device *dev, struct sk_buff *skb);
#endif
@@ -404,7 +409,7 @@ woal_init_sw(moal_handle * handle)
/* PnP and power profile */
handle->surprise_removed = MFALSE;
init_waitqueue_head(&handle->init_wait_q);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
spin_lock_init(&handle->queue_lock);
#endif
@@ -1215,9 +1220,7 @@ const struct net_device_ops woal_netdev_ops = {
#else
.ndo_set_multicast_list = woal_set_multicast_list,
#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)
.ndo_select_queue = woal_select_queue,
-#endif
};
#endif
@@ -1292,9 +1295,7 @@ const struct net_device_ops woal_uap_netdev_ops = {
#else
.ndo_set_multicast_list = woal_uap_set_multicast_list,
#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)
.ndo_select_queue = woal_select_queue,
-#endif
};
#endif
@@ -1373,7 +1374,7 @@ woal_add_interface(moal_handle * handle, t_u8 bss_index, t_u8 bss_type)
moal_private *priv = NULL;
ENTER();
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
#define MAX_WMM_QUEUE 4
/* Allocate an Ethernet device */
if (!(dev = alloc_etherdev_mq(sizeof(moal_private), MAX_WMM_QUEUE))) {
@@ -1420,11 +1421,8 @@ woal_add_interface(moal_handle * handle, t_u8 bss_index, t_u8 bss_type)
else if (bss_type == MLAN_BSS_TYPE_WIFIDIRECT)
priv->bss_role = MLAN_BSS_ROLE_STA;
#endif
-#if defined(STA_CFG80211) || defined(UAP_CFG80211)
- priv->probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
-#endif
-#ifdef STA_SUPPORT
-#endif
+
+ INIT_LIST_HEAD(&priv->tcp_sess_queue);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
SET_MODULE_OWNER(dev);
@@ -1448,7 +1446,7 @@ woal_add_interface(moal_handle * handle, t_u8 bss_index, t_u8 bss_type)
if ((priv->bss_role == MLAN_BSS_ROLE_STA) && IS_STA_CFG80211(cfg80211_wext)) {
if (bss_type == MLAN_BSS_TYPE_STA
#if defined(WIFI_DIRECT_SUPPORT)
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) || defined(COMPAT_WIRELESS)
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
|| bss_type == MLAN_BSS_TYPE_WIFIDIRECT
#endif
#endif
@@ -1883,7 +1881,14 @@ woal_close(struct net_device *dev)
moal_private *priv = (moal_private *) netdev_priv(dev);
ENTER();
-
+#ifdef STA_SUPPORT
+#ifdef STA_CFG80211
+ if (IS_STA_CFG80211(cfg80211_wext) && priv->scan_request) {
+ cfg80211_scan_done(priv->scan_request, MTRUE);
+ priv->scan_request = NULL;
+ }
+#endif
+#endif
woal_stop_queue(priv->netdev);
MODULE_PUT;
@@ -2066,7 +2071,7 @@ woal_get_stats(struct net_device *dev)
return &priv->stats;
}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
/**
* @brief This function handles wmm queue select
*
@@ -2109,6 +2114,233 @@ woal_select_queue(struct net_device * dev, struct sk_buff * skb)
#endif
/**
+ * @brief This function gets tcp session from the tcp session queue
+ *
+ * @param priv A pointer to moal_private structure
+ * @param src_ip IP address of the device
+ * @param src_port TCP port of the device
+ * @param dst_ip IP address of the client
+ * @param src_port TCP port of the client
+ *
+ * @return A pointer to the tcp session data structure, if found.
+ * Otherwise, null
+ */
+struct tcp_sess *
+woal_get_tcp_sess(moal_private * priv,
+ t_u32 src_ip, t_u16 src_port, t_u32 dst_ip, t_u16 dst_port)
+{
+ struct tcp_sess *tcp_sess = NULL;
+ ENTER();
+
+ list_for_each_entry(tcp_sess, &priv->tcp_sess_queue, link) {
+ if ((tcp_sess->src_ip_addr == src_ip) &&
+ (tcp_sess->src_tcp_port == src_port) &&
+ (tcp_sess->dst_ip_addr == dst_ip) &&
+ (tcp_sess->dst_tcp_port == dst_port)) {
+ LEAVE();
+ return tcp_sess;
+ }
+ }
+ LEAVE();
+ return NULL;
+}
+
+/**
+ * @brief This function checks received tcp packet for FIN
+ * and release the tcp session if received
+ *
+ * @param priv A pointer to moal_private structure
+ * @param skb A pointer to sk_buff structure
+ *
+ * @return None
+ */
+void
+woal_check_tcp_fin(moal_private * priv, struct sk_buff *skb)
+{
+ struct ethhdr *ethh = NULL;
+ struct iphdr *iph = NULL;
+ struct tcphdr *tcph = NULL;
+ struct tcp_sess *tcp_sess = NULL;
+
+ ENTER();
+
+ ethh = eth_hdr(skb);
+ if (ntohs(ethh->h_proto) == ETH_P_IP) {
+ iph = (struct iphdr *) ((t_u8 *) ethh + sizeof(struct ethhdr));
+ if (iph->protocol == IPPROTO_TCP) {
+ tcph = (struct tcphdr *) ((t_u8 *) iph + iph->ihl * 4);
+ if (tcph->fin) {
+ tcp_sess = woal_get_tcp_sess(priv, iph->daddr,
+ tcph->dest, iph->saddr,
+ tcph->source);
+ if (tcp_sess != NULL) {
+ PRINTM(MINFO,
+ "TX: release a tcp session in dl. (src: ipaddr 0x%08x, port: %d. dst: ipaddr 0x%08x, port: %d\n",
+ iph->daddr, tcph->dest, iph->saddr, tcph->source);
+ /* remove the tcp session from the queue */
+ list_del(&tcp_sess->link);
+ kfree(tcp_sess);
+ } else {
+ PRINTM(MINFO, "Tx: released TCP session is not found.\n ");
+ }
+ }
+ }
+ }
+ LEAVE();
+}
+
+/**
+ * @brief This function process tcp ack packets
+ *
+ * @param priv A pointer to moal_private structure
+ * @param pmbuf A pointer to the mlan buffer associated with the skb
+ *
+ * @return 1, if a tcp ack packet has been dropped. Otherwise, 0.
+ */
+int
+woal_process_tcp_ack(moal_private * priv, mlan_buffer * pmbuf)
+{
+ int ret = 0;
+ struct ethhdr *ethh = NULL;
+ struct iphdr *iph = NULL;
+ struct tcphdr *tcph = NULL;
+ struct tcp_sess *tcp_sess = NULL;
+ struct sk_buff *skb = NULL;
+ t_u32 ack_seq = 0;
+ t_u32 len = 0;
+ t_u8 opt = 0;
+ t_u8 opt_len = 0;
+ t_u8 *pos = NULL;
+ t_u32 win_size = 0;
+
+#define TCP_ACK_DELAY 3
+#define TCP_ACK_INIT_WARMING_UP 1000 /* initial */
+#define TCP_ACK_RECV_WARMING_UP 1000 /* recovery */
+
+ ENTER();
+
+ /** check the tcp packet */
+ ethh = (struct ethhdr *) (pmbuf->pbuf + pmbuf->data_offset);
+ if (ntohs(ethh->h_proto) != ETH_P_IP) {
+ return 0;
+ }
+ iph = (struct iphdr *) ((t_u8 *) ethh + sizeof(struct ethhdr));
+ if (iph->protocol != IPPROTO_TCP) {
+ return 0;
+ }
+ tcph = (struct tcphdr *) ((t_u8 *) iph + iph->ihl * 4);
+
+ if (tcph->syn & tcph->ack) {
+ /* respond to a TCP request. create a tcp session */
+ if (!(tcp_sess = kmalloc(sizeof(struct tcp_sess), GFP_ATOMIC))) {
+ PRINTM(MERROR, "Fail to allocate tcp_sess.\n");
+ return 0;
+ }
+ memset(tcp_sess, 0, sizeof(struct tcp_sess));
+ tcp_sess->src_ip_addr = iph->saddr; /* my ip addr */
+ tcp_sess->dst_ip_addr = iph->daddr;
+ tcp_sess->src_tcp_port = tcph->source;
+ tcp_sess->dst_tcp_port = tcph->dest;
+ tcp_sess->start_cnt = TCP_ACK_INIT_WARMING_UP;
+
+ INIT_LIST_HEAD(&tcp_sess->link);
+ list_add_tail(&tcp_sess->link, &priv->tcp_sess_queue);
+ PRINTM(MINFO,
+ "create a tcp session. (src: ipaddr 0x%08x, port: %d. dst: ipaddr 0x%08x, port: %d\n",
+ iph->saddr, tcph->source, iph->daddr, tcph->dest);
+
+ /* parse tcp options for the window scale */
+ len = (tcph->doff * 4) - sizeof(struct tcphdr);
+ pos = (t_u8 *) (tcph + 1);
+ while (len > 0) {
+ opt = *pos++;
+ switch (opt) {
+ case TCPOPT_EOL:
+ len = 0;
+ continue;
+ case TCPOPT_NOP:
+ len--;
+ continue;
+ case TCPOPT_WINDOW:
+ opt_len = *pos++;
+ if (opt_len == TCPOLEN_WINDOW) {
+ tcp_sess->rx_win_scale = *pos;
+ tcp_sess->rx_win_opt = 1;
+ if (tcp_sess->rx_win_scale > 14)
+ tcp_sess->rx_win_scale = 14;
+ PRINTM(MINFO, "TCP Window Scale: %d \n",
+ tcp_sess->rx_win_scale);
+ }
+ break;
+ default:
+ opt_len = *pos++;
+ }
+ len -= opt_len;
+ pos += opt_len - 2;
+ }
+ } else if (tcph->ack && !(tcph->syn) &&
+ (ntohs(iph->tot_len) == (iph->ihl * 4 + tcph->doff * 4))) {
+ /** it is an ack packet, not a piggyback ack */
+ tcp_sess = woal_get_tcp_sess(priv, iph->saddr, tcph->source,
+ iph->daddr, tcph->dest);
+ if (tcp_sess == NULL) {
+ return 0;
+ }
+ /** do not drop the ack packets initially */
+ if (tcp_sess->start_cnt) {
+ tcp_sess->start_cnt--;
+ return 0;
+ }
+
+ /* check the window size. */
+ win_size = ntohs(tcph->window);
+ if (tcp_sess->rx_win_opt) {
+ win_size <<= tcp_sess->rx_win_scale;
+ /* Note: it may depend on the rtd */
+ if ((win_size > 1500 * (TCP_ACK_DELAY + 5)) &&
+ (tcp_sess->ack_cnt < TCP_ACK_DELAY)) {
+ /* if windiow is big enough, drop the ack packet */
+ if (tcp_sess->ack_seq != ntohl(tcph->ack_seq)) {
+ ack_seq = tcp_sess->ack_seq;
+ tcp_sess->ack_seq = ntohl(tcph->ack_seq);
+ tcp_sess->ack_cnt++;
+ skb = (struct sk_buff *) pmbuf->pdesc;
+ if (skb)
+ dev_kfree_skb_any(skb);
+ ret = 1;
+ } else {
+ /* the ack packet is retransmitted. thus, stop dropping
+ the ack packets */
+ tcp_sess->start_cnt = TCP_ACK_RECV_WARMING_UP;
+ PRINTM(MINFO, "Recover the TCP session.\n ");
+ }
+ } else {
+ /* send the current ack pacekt */
+ ack_seq = tcp_sess->ack_seq;
+ tcp_sess->ack_seq = ntohl(tcph->ack_seq);
+ tcp_sess->ack_cnt = 0;
+ ret = 0;
+ }
+ }
+ } else if (tcph->fin) {
+ tcp_sess = woal_get_tcp_sess(priv, iph->saddr, tcph->source,
+ iph->daddr, tcph->dest);
+ if (tcp_sess != NULL) {
+ /* remove the tcp session from the queue */
+ PRINTM(MINFO,
+ "Rx: release a tcp session in ul. (src: ipaddr 0x%08x, port: %d. dst: ipaddr 0x%08x, port: %d\n",
+ iph->saddr, tcph->source, iph->daddr, tcph->dest);
+ list_del(&tcp_sess->link);
+ kfree(tcp_sess);
+ } else {
+ PRINTM(MINFO, "released TCP session is not found.\n ");
+ }
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
* @brief This function handles packet transmission
*
* @param skb A pointer to sk_buff structure
@@ -2165,6 +2397,13 @@ woal_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
memset((t_u8 *) pmbuf, 0, sizeof(mlan_buffer));
pmbuf->bss_index = priv->bss_index;
woal_fill_mlan_buffer(priv, pmbuf, skb);
+ if (priv->enable_tcp_ack_enh == MTRUE) {
+ if (woal_process_tcp_ack(priv, pmbuf)) {
+ /* the ack packet has been dropped */
+ goto done;
+ }
+ }
+
status = mlan_send_packet(priv->phandle->pmlan_adapter, pmbuf);
switch (status) {
case MLAN_STATUS_PENDING:
@@ -2394,6 +2633,8 @@ woal_set_multicast_list(struct net_device *dev)
void
woal_init_priv(moal_private * priv, t_u8 wait_option)
{
+ struct list_head *link = NULL;
+ struct tcp_sess *tcp_sess = NULL;
ENTER();
#ifdef STA_SUPPORT
if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
@@ -2414,7 +2655,7 @@ woal_init_priv(moal_private * priv, t_u8 wait_option)
if (IS_STA_CFG80211(cfg80211_wext)) {
if (priv->bss_type == MLAN_BSS_TYPE_STA
#if defined(WIFI_DIRECT_SUPPORT)
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) || defined(COMPAT_WIRELESS)
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
|| priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT
#endif
#endif
@@ -2434,6 +2675,25 @@ woal_init_priv(moal_private * priv, t_u8 wait_option)
}
#endif
priv->media_connected = MFALSE;
+
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ priv->probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+#endif
+#ifdef STA_SUPPORT
+#endif
+
+ priv->enable_tcp_ack_enh = MTRUE;
+ while (!list_empty(&priv->tcp_sess_queue)) {
+ link = priv->tcp_sess_queue.next;
+ tcp_sess = list_entry(link, struct tcp_sess, link);
+ PRINTM(MINFO,
+ "warm reset: release a tcp session in dl. (src: ipaddr 0x%08x, port: %d. dst: ipaddr 0x%08x, port: %d\n",
+ tcp_sess->src_ip_addr, tcp_sess->src_tcp_port,
+ tcp_sess->dst_ip_addr, tcp_sess->dst_tcp_port);
+ list_del(link);
+ kfree(tcp_sess);
+ }
+
woal_request_get_fw_info(priv, wait_option, NULL);
LEAVE();
@@ -2805,8 +3065,9 @@ woal_reassociation_thread(void *data)
for (i = 0; i < handle->priv_num && (priv = handle->priv[i]); i++) {
- if (priv->reassoc_required == MFALSE)
+ if (priv->reassoc_required == MFALSE) {
continue;
+ }
memset(&bss_info, 0x00, sizeof(bss_info));
@@ -2892,7 +3153,6 @@ woal_reassociation_thread(void *data)
mlan_ioctl_req *req = NULL;
reassoc_timer_req = MFALSE;
-
if (priv->rate_index != AUTO_RATE) {
req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
@@ -2928,11 +3188,13 @@ woal_reassociation_thread(void *data)
break;
if (reassoc_timer_req == MTRUE) {
- PRINTM(MEVENT,
- "Reassoc: No AP found or assoc failed. "
- "Restarting re-assoc Timer: %d\n", (int) timer_val);
handle->is_reassoc_timer_set = MTRUE;
- woal_mod_timer(&handle->reassoc_timer, timer_val);
+ {
+ PRINTM(MEVENT,
+ "Reassoc: No AP found or assoc failed. "
+ "Restarting re-assoc Timer: %d\n", (int) timer_val);
+ woal_mod_timer(&handle->reassoc_timer, timer_val);
+ }
}
}
woal_deactivate_thread(pmoal_thread);
@@ -3083,7 +3345,7 @@ woal_moal_debug_info(moal_private * priv, moal_handle * handle, u8 flag)
{
moal_handle *phandle = NULL;
char buf[MLAN_MAX_VER_STR_LEN];
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
int i = 0;
#endif
@@ -3122,7 +3384,7 @@ woal_moal_debug_info(moal_private * priv, moal_handle * handle, u8 flag)
MFALSE) ? "Disconnected" : "Connected"));
PRINTM(MERROR, "carrier %s\n",
((netif_carrier_ok(priv->netdev)) ? "on" : "off"));
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
for (i = 0; i < (priv->netdev->num_tx_queues); i++) {
PRINTM(MERROR, "tx queue %d: %s\n", i,
((netif_tx_queue_stopped
@@ -3599,11 +3861,11 @@ woal_init_module(void)
/* Init mutex */
MOAL_INIT_SEMAPHORE(&AddRemoveCardSem);
+ wifi_add_dev();
+
/* Register with bus */
ret = woal_bus_register();
- wifi_add_dev();
-
LEAVE();
return ret;
}
@@ -3645,7 +3907,8 @@ woal_cleanup_module(void)
if (handle->priv[i]->media_connected == MTRUE)
woal_disconnect(handle->priv[i], MOAL_CMD_WAIT, NULL);
#ifdef STA_CFG80211
- if (handle->priv[i]->scan_request) {
+ if (IS_STA_CFG80211(cfg80211_wext) &&
+ handle->priv[i]->scan_request) {
cfg80211_scan_done(handle->priv[i]->scan_request, MTRUE);
handle->priv[i]->scan_request = NULL;
}
@@ -3681,13 +3944,13 @@ woal_cleanup_module(void)
MOAL_CMD_WAIT);
}
- wifi_del_dev();
-
exit:
MOAL_REL_SEMAPHORE(&AddRemoveCardSem);
exit_sem_err:
/* Unregister from bus */
woal_bus_unregister();
+ wifi_del_dev();
+
LEAVE();
}
@@ -3749,7 +4012,7 @@ module_param(init_cfg, charp, 0);
MODULE_PARM_DESC(init_cfg, "Init config file name");
module_param(cal_data_cfg, charp, 0);
MODULE_PARM_DESC(cal_data_cfg, "Calibration data file name");
-module_param(minicard_pwrup, int, 0);
+module_param(minicard_pwrup, int, 1);
MODULE_PARM_DESC(minicard_pwrup,
"1: Driver load clears PDn/Rst, unload sets (default); 0: Don't do this.");
module_param(cfg80211_wext, int, 0);
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_main.h b/drivers/net/wireless/sd8797/mlinux/moal_main.h
index cd1fdd8244c1..32426a149779 100644
--- a/drivers/net/wireless/sd8797/mlinux/moal_main.h
+++ b/drivers/net/wireless/sd8797/mlinux/moal_main.h
@@ -2,7 +2,7 @@
*
* @brief This file contains wlan driver specific defines etc.
*
- * Copyright (C) 2008-2011, Marvell International Ltd.
+ * Copyright (C) 2008-2012, Marvell International Ltd.
*
* This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
@@ -49,8 +49,9 @@ Change log:
#include <linux/ctype.h>
#include <linux/proc_fs.h>
#include <linux/vmalloc.h>
-#include <linux/ptrace.h>
-#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/string.h>
+#include <linux/list.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
#include <linux/config.h>
@@ -654,6 +655,24 @@ struct debug_data_priv
/** IP address operation: Remove */
#define IPADDR_OP_REMOVE 0
+struct tcp_sess
+{
+ struct list_head link;
+ /** tcp session info */
+ t_u32 src_ip_addr;
+ t_u32 dst_ip_addr;
+ t_u16 src_tcp_port;
+ t_u16 dst_tcp_port;
+ /** tcp window info */
+ t_u8 rx_win_opt;
+ t_u32 rx_win_scale;
+ /** warming up counter */
+ t_u32 start_cnt;
+ /** tx ack packet info */
+ t_u32 ack_seq;
+ t_u32 ack_cnt;
+};
+
/** Private structure for MOAL */
struct _moal_private
{
@@ -715,6 +734,18 @@ struct _moal_private
t_u8 cfg_bssid[ETH_ALEN];
/** Disconnect request from CFG80211 */
bool cfg_disconnect;
+ /** rssi_threshold */
+ s32 cqm_rssi_thold;
+ /** rssi hysteresis */
+ u32 cqm_rssi_hyst;
+ /** last rssi_low */
+ u8 last_rssi_low;
+ /** last rssi_high */
+ u8 last_rssi_high;
+ /** mrvl rssi threshold */
+ u8 mrvl_rssi_low;
+ /** rssi status */
+ u32 rssi_status;
#endif /* STA_SUPPORT */
#endif /* STA_CFG80211 */
/** IOCTL wait queue */
@@ -779,6 +810,11 @@ struct _moal_private
/** MLAN debug info */
struct debug_data_priv items_priv;
#endif
+
+ /** tcp session queue */
+ struct list_head tcp_sess_queue;
+ /** TCP Ack enhance flag */
+ t_u8 enable_tcp_ack_enh;
};
/** Handle data structure for MOAL */
@@ -818,6 +854,7 @@ struct _moal_handle
t_u16 init_wait_q_woken;
/** Init wait queue */
wait_queue_head_t init_wait_q __ATTRIB_ALIGN__;
+#if defined(SDIO_SUSPEND_RESUME)
/** Device suspend flag */
BOOLEAN is_suspended;
#ifdef SDIO_SUSPEND_RESUME
@@ -830,6 +867,7 @@ struct _moal_handle
t_u16 hs_activate_wait_q_woken;
/** Host Sleep activated event wait queue */
wait_queue_head_t hs_activate_wait_q __ATTRIB_ALIGN__;
+#endif
/** Card pointer */
t_void *card;
/** Rx pending in MLAN */
@@ -844,12 +882,14 @@ struct _moal_handle
t_u32 lock_count;
/** mlan buffer alloc count */
t_u32 mbufalloc_count;
+#if defined(SDIO_SUSPEND_RESUME)
/** hs skip count */
t_u32 hs_skip_count;
/** hs force count */
t_u32 hs_force_count;
/** suspend_fail flag */
BOOLEAN suspend_fail;
+#endif
#ifdef REASSOCIATION
/** Re-association thread */
moal_thread reassoc_thread;
@@ -923,7 +963,7 @@ struct _moal_handle
t_u8 cmd52_reg;
/** cmd52 value */
t_u8 cmd52_val;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
/** spinlock to stop_queue/wake_queue*/
spinlock_t queue_lock;
#endif
@@ -939,7 +979,7 @@ struct _moal_handle
static inline void
woal_set_trans_start(struct net_device *dev)
{
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)
unsigned int i;
for (i = 0; i < dev->num_tx_queues; i++) {
netdev_get_tx_queue(dev, i)->trans_start = jiffies;
@@ -958,7 +998,7 @@ woal_set_trans_start(struct net_device *dev)
static inline void
woal_start_queue(struct net_device *dev)
{
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
netif_start_queue(dev);
#else
netif_tx_start_all_queues(dev);
@@ -975,7 +1015,7 @@ woal_start_queue(struct net_device *dev)
static inline void
woal_stop_queue(struct net_device *dev)
{
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
unsigned long flags;
moal_private *priv = (moal_private *) netdev_priv(dev);
spin_lock_irqsave(&priv->phandle->queue_lock, flags);
@@ -1000,7 +1040,7 @@ woal_stop_queue(struct net_device *dev)
static inline void
woal_wake_queue(struct net_device *dev)
{
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
unsigned long flags;
moal_private *priv = (moal_private *) netdev_priv(dev);
spin_lock_irqsave(&priv->phandle->queue_lock, flags);
@@ -1217,6 +1257,8 @@ typedef struct _HostCmd_DS_802_11_CFG_DATA
#define WEXT_BGSCAN_RSSI_SECTION 'R'
/** BGSCAN SCAN INTERVAL SECTION */
#define WEXT_BGSCAN_INTERVAL_SECTION 'T'
+/** BGSCAN REPEAT SECTION */
+#define WEXT_BGSCAN_REPEAT_SECTION 'E'
/** band AUTO */
#define WIFI_FREQUENCY_BAND_AUTO 0
@@ -1316,11 +1358,15 @@ mlan_status woal_set_get_hs_params(moal_private * priv, t_u16 action,
t_u8 wait_option, mlan_ds_hs_cfg * hscfg);
/** Cancel Host Sleep configuration */
mlan_status woal_cancel_hs(moal_private * priv, t_u8 wait_option);
+#if defined(SDIO_SUSPEND_RESUME)
/** Enable Host Sleep configuration */
int woal_enable_hs(moal_private * priv);
/** hs active timeout 2 second */
#define HS_ACTIVE_TIMEOUT (2 * HZ)
+#endif
+/** get deep sleep */
+int woal_get_deep_sleep(moal_private * priv, t_u32 * data);
/** set deep sleep */
int woal_set_deep_sleep(moal_private * priv, t_u8 wait_option,
BOOLEAN bdeep_sleep, t_u16 idletime);
@@ -1431,6 +1477,8 @@ int woal_host_command(moal_private * priv, struct iwreq *wrq);
#if defined(WIFI_DIRECT_SUPPORT)
#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
#if defined(STA_WEXT) || defined(UAP_WEXT)
+mlan_status woal_bss_role_cfg(moal_private * priv, t_u8 action,
+ t_u8 wait_option, t_u8 * bss_role);
int woal_set_get_bss_role(moal_private * priv, struct iwreq *wrq);
#endif
#endif
@@ -1443,8 +1491,8 @@ int woal_hostcmd_ioctl(struct net_device *dev, struct ifreq *req);
#if defined(WIFI_DIRECT_SUPPORT)
mlan_status woal_set_remain_channel_ioctl(moal_private * priv, t_u8 wait_option,
mlan_ds_remain_chan * pchan);
-mlan_status woal_cfg80211_wifi_direct_mode_cfg(moal_private * priv,
- t_u16 action, t_u16 * mode);
+mlan_status woal_wifi_direct_mode_cfg(moal_private * priv, t_u16 action,
+ t_u16 * mode);
#endif /* WIFI_DIRECT_SUPPORT */
#ifdef CONFIG_PROC_FS
@@ -1502,9 +1550,15 @@ mlan_status woal_remove_rxfilter(moal_private * priv, char *rxfilter);
mlan_status woal_set_qos_cfg(moal_private * priv, char *qos_cfg);
int woal_set_sleeppd(moal_private * priv, char *psleeppd);
mlan_status woal_set_rssi_low_threshold(moal_private * priv, char *rssi);
+mlan_status woal_set_rssi_threshold(moal_private * priv, t_u32 event_id);
mlan_status woal_set_bg_scan(moal_private * priv, char *buf, int length);
mlan_status woal_stop_bg_scan(moal_private * priv);
void woal_reconfig_bgscan(moal_handle * handle);
#endif
+struct tcp_sess *woal_get_tcp_sess(moal_private * priv,
+ t_u32 src_ip, t_u16 src_port,
+ t_u32 dst_ip, t_u16 dst_port);
+void woal_check_tcp_fin(moal_private * priv, struct sk_buff *skb);
+
#endif /* _MOAL_MAIN_H */
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_priv.c b/drivers/net/wireless/sd8797/mlinux/moal_priv.c
index e3e4b844e11b..9a5173ddfb3f 100644
--- a/drivers/net/wireless/sd8797/mlinux/moal_priv.c
+++ b/drivers/net/wireless/sd8797/mlinux/moal_priv.c
@@ -101,6 +101,13 @@ woal_warm_reset(moal_private * priv)
moal_handle *handle = priv->phandle;
mlan_ioctl_req *req = NULL;
mlan_ds_misc_cfg *misc = NULL;
+#if defined(WIFI_DIRECT_SUPPORT)
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+ t_u8 bss_role = MLAN_BSS_ROLE_STA;
+#endif
+#endif
+#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
ENTER();
@@ -110,8 +117,24 @@ woal_warm_reset(moal_private * priv)
ret = woal_reset_intf(priv, MOAL_IOCTL_WAIT, MTRUE);
/* Initialize private structures */
- for (intf_num = 0; intf_num < handle->priv_num; intf_num++)
+ for (intf_num = 0; intf_num < handle->priv_num; intf_num++) {
woal_init_priv(handle->priv[intf_num], MOAL_IOCTL_WAIT);
+#if defined(WIFI_DIRECT_SUPPORT)
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+ if (handle->priv[intf_num]->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) {
+ if (MLAN_STATUS_SUCCESS != woal_bss_role_cfg(handle->priv[intf_num],
+ MLAN_ACT_SET,
+ MOAL_IOCTL_WAIT,
+ &bss_role)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+#endif /* STA_WEXT || UAP_WEXT */
+#endif /* STA_SUPPORT && UAP_SUPPORT */
+#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
+ }
/* Restart the firmware */
req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
@@ -334,48 +357,6 @@ woal_get_signal(moal_private * priv, struct iwreq *wrq)
}
/**
- * @brief Get Deep Sleep
- *
- * @param priv Pointer to the moal_private driver data struct
- * @param deep_sleep Pointer to return deep_sleep setting
- *
- * @return 0 --success, otherwise fail
- */
-static int
-woal_get_deep_sleep(moal_private * priv, t_u32 * data)
-{
- int ret = 0;
- mlan_ioctl_req *req = NULL;
- mlan_ds_pm_cfg *pm = NULL;
-
- ENTER();
-
- req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
- if (req == NULL) {
- LEAVE();
- return -ENOMEM;
- }
- pm = (mlan_ds_pm_cfg *) req->pbuf;
- pm->sub_command = MLAN_OID_PM_CFG_DEEP_SLEEP;
- req->req_id = MLAN_IOCTL_PM_CFG;
-
- req->action = MLAN_ACT_GET;
- if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
- ret = -EFAULT;
- goto done;
- }
- *data = pm->param.auto_deep_sleep.auto_ds;
- *(data + 1) = pm->param.auto_deep_sleep.idletime;
-
- done:
- if (req)
- kfree(req);
-
- LEAVE();
- return ret;
-}
-
-/**
* @brief Get/Set DeepSleep mode
*
* @param priv Pointer to the moal_private driver data struct
@@ -3692,7 +3673,6 @@ static int
woal_set_get_ip_addr(moal_private * priv, struct iwreq *wrq)
{
char buf[IPADDR_MAX_BUF];
- struct iwreq *wreq = (struct iwreq *) wrq;
mlan_ioctl_req *ioctl_req = NULL;
mlan_ds_misc_cfg *misc = NULL;
int ret = 0, op_code = 0, data_length = wrq->u.data.length;
@@ -3710,8 +3690,8 @@ woal_set_get_ip_addr(moal_private * priv, struct iwreq *wrq)
if (data_length <= 1) { /* GET */
ioctl_req->action = MLAN_ACT_GET;
} else {
- if (copy_from_user(buf, wreq->u.data.pointer,
- MIN(IPADDR_MAX_BUF - 1, wreq->u.data.length))) {
+ if (copy_from_user(buf, wrq->u.data.pointer,
+ MIN(IPADDR_MAX_BUF - 1, wrq->u.data.length))) {
PRINTM(MERROR, "Copy from user failed\n");
ret = -EFAULT;
goto done;
@@ -3727,7 +3707,7 @@ woal_set_get_ip_addr(moal_private * priv, struct iwreq *wrq)
ioctl_req->action = MLAN_ACT_SET;
/* only one IP is supported in current firmware */
memset(misc->param.ipaddr_cfg.ip_addr[0], 0, IPADDR_LEN);
- in4_pton(&buf[2], MIN((IPADDR_MAX_BUF - 3), (wreq->u.data.length - 2)),
+ in4_pton(&buf[2], MIN((IPADDR_MAX_BUF - 3), (wrq->u.data.length - 2)),
misc->param.ipaddr_cfg.ip_addr[0], ' ', NULL);
/* only one IP is supported in current firmware */
misc->param.ipaddr_cfg.ip_addr_num = 1;
@@ -4525,6 +4505,34 @@ woal_get_scan_table_ioctl(moal_private * priv, struct iwreq *wrq)
}
/**
+ * @brief Set user scan ext -- Async mode, without wait
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_set_user_scan_ext_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ wlan_user_scan_cfg scan_req;
+ ENTER();
+ memset(&scan_req, 0x00, sizeof(scan_req));
+ if (copy_from_user
+ (&scan_req, wrq->u.data.pointer,
+ MIN(wrq->u.data.length, sizeof(scan_req)))) {
+ PRINTM(MINFO, "Copy from user failed\n");
+ LEAVE();
+ return -EFAULT;
+ }
+ if (MLAN_STATUS_FAILURE == woal_do_scan(priv, &scan_req))
+ ret = -EFAULT;
+ LEAVE();
+ return ret;
+}
+
+/**
* @brief Set user scan
*
* @param priv A pointer to moal_private structure
@@ -5912,6 +5920,86 @@ woal_mgmt_frame_passthru_ctrl(moal_private * priv, struct iwreq *wrq)
}
/**
+ * @brief Set/Get CFP table codes
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_cfp_code(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ int data[2];
+ int data_length = wrq->u.data.length;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc_cfg = NULL;
+ mlan_ds_misc_cfp_code *cfp_code = NULL;
+
+ ENTER();
+
+ if (data_length > 2) {
+ PRINTM(MERROR, "Invalid number of argument!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ misc_cfg = (mlan_ds_misc_cfg *) req->pbuf;
+ cfp_code = &misc_cfg->param.cfp_code;
+ misc_cfg->sub_command = MLAN_OID_MISC_CFP_CODE;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ if (!data_length) {
+ req->action = MLAN_ACT_GET;
+ } else {
+ if (copy_from_user
+ (data, wrq->u.data.pointer, sizeof(int) * data_length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ cfp_code->cfp_code_bg = data[0];
+ if (data_length == 2)
+ cfp_code->cfp_code_a = data[1];
+ req->action = MLAN_ACT_SET;
+ }
+
+ /* Send IOCTL request to MLAN */
+ if (woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT) != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (!data_length) {
+ data[0] = cfp_code->cfp_code_bg;
+ data[1] = cfp_code->cfp_code_a;
+ data_length = 2;
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int) * data_length)) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = data_length;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
* @brief Set/Get Tx/Rx antenna
*
* @param priv A pointer to moal_private structure
@@ -6183,6 +6271,9 @@ woal_wext_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
case WOAL_MGMT_FRAME_CTRL:
ret = woal_mgmt_frame_passthru_ctrl(priv, wrq);
break;
+ case WOAL_CFP_CODE:
+ ret = woal_cfp_code(priv, wrq);
+ break;
case WOAL_SET_GET_TX_RX_ANT:
ret = woal_set_get_tx_rx_ant(priv, wrq);
break;
@@ -6296,6 +6387,9 @@ woal_wext_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
case WOAL_GET_SCAN_TABLE:
ret = woal_get_scan_table_ioctl(priv, wrq);
break;
+ case WOAL_SET_USER_SCAN_EXT:
+ ret = woal_set_user_scan_ext_ioctl(priv, wrq);
+ break;
case WOAL_WMM_ADDTS:
ret = woal_wmm_addts_req_ioctl(priv, wrq);
break;
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_priv.h b/drivers/net/wireless/sd8797/mlinux/moal_priv.h
index de491f6d6a29..1c24f30502f6 100644
--- a/drivers/net/wireless/sd8797/mlinux/moal_priv.h
+++ b/drivers/net/wireless/sd8797/mlinux/moal_priv.h
@@ -115,6 +115,8 @@ Change log:
/** Private command ID to set/get dfs testing settings */
#define WOAL_DFS_TESTING 33
#endif
+/** Private command ID to set/get CFP table codes */
+#define WOAL_CFP_CODE 34
/** Private command ID to set/get tx/rx antenna */
#define WOAL_SET_GET_TX_RX_ANT 35
/** Private command ID to set/get management frame passthru mask */
@@ -226,6 +228,8 @@ Change log:
#define WOAL_SET_USER_SCAN 3
/** Private command ID for getscantable */
#define WOAL_GET_SCAN_TABLE 4
+/** Private command ID for setuserscanext: async without wait */
+#define WOAL_SET_USER_SCAN_EXT 5
/** Private command ID to request ADDTS */
#define WOAL_WMM_ADDTS 7
@@ -526,6 +530,11 @@ static const struct iw_priv_args woal_private_args[] = {
IW_PRIV_TYPE_INT | 16,
"mgmtframectrl"},
{
+ WOAL_CFP_CODE,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "cfpcode"},
+ {
WOAL_SET_GET_TX_RX_ANT,
IW_PRIV_TYPE_INT | 16,
IW_PRIV_TYPE_INT | 16,
@@ -656,6 +665,11 @@ static const struct iw_priv_args woal_private_args[] = {
IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
"getscantable"},
{
+ WOAL_SET_USER_SCAN_EXT,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ "setuserscanext"},
+ {
WOAL_WMM_ADDTS,
IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_proc.c b/drivers/net/wireless/sd8797/mlinux/moal_proc.c
index e98803c2e3fb..fb7c63a29cab 100644
--- a/drivers/net/wireless/sd8797/mlinux/moal_proc.c
+++ b/drivers/net/wireless/sd8797/mlinux/moal_proc.c
@@ -95,9 +95,9 @@ woal_info_proc_read(char *page, char **start, off_t offset,
int mc_count = netdev_mc_count(netdev);
#endif /* < 2.6.35 */
#else
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
int i = 0;
-#endif /* >= 2.6.34 */
+#endif /* >= 2.6.29 */
#endif
#ifdef UAP_SUPPORT
mlan_ds_uap_stats ustats;
@@ -199,7 +199,7 @@ woal_info_proc_read(char *page, char **start, off_t offset,
p += sprintf(p, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors);
p += sprintf(p, "carrier %s\n",
((netif_carrier_ok(priv->netdev)) ? "on" : "off"));
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
for (i = 0; i < netdev->num_tx_queues; i++) {
p += sprintf(p, "tx queue %d: %s\n", i,
((netif_tx_queue_stopped(netdev_get_tx_queue(netdev, 0))) ?
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_sdio_mmc.c b/drivers/net/wireless/sd8797/mlinux/moal_sdio_mmc.c
index 96e3e971936f..f09f33e6435d 100644
--- a/drivers/net/wireless/sd8797/mlinux/moal_sdio_mmc.c
+++ b/drivers/net/wireless/sd8797/mlinux/moal_sdio_mmc.c
@@ -315,6 +315,12 @@ woal_sdio_suspend(struct device *dev)
}
handle = cardp->handle;
+ if (handle->is_suspended == MTRUE) {
+ PRINTM(MWARN, "Device already suspended\n");
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+
handle->suspend_fail = MFALSE;
memset(&pm_info, 0, sizeof(pm_info));
if (MLAN_STATUS_SUCCESS ==
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_shim.c b/drivers/net/wireless/sd8797/mlinux/moal_shim.c
index e33a6e38067a..25cfdc549f3d 100644
--- a/drivers/net/wireless/sd8797/mlinux/moal_shim.c
+++ b/drivers/net/wireless/sd8797/mlinux/moal_shim.c
@@ -745,6 +745,11 @@ moal_recv_packet(IN t_void * pmoal_handle, IN pmlan_buffer pmbuf)
skb->dev = priv->netdev;
skb->protocol = eth_type_trans(skb, priv->netdev);
skb->ip_summed = CHECKSUM_NONE;
+
+ if (priv->enable_tcp_ack_enh == MTRUE) {
+ woal_check_tcp_fin(priv, skb);
+ }
+
priv->stats.rx_bytes += skb->len;
priv->stats.rx_packets++;
if (in_interrupt())
@@ -950,6 +955,13 @@ moal_recv_event(IN t_void * pmoal_handle, IN pmlan_event pmevent)
#endif
}
#endif /* STA_WEXT */
+#ifdef STA_CFG80211
+ if (IS_STA_CFG80211(cfg80211_wext)) {
+ cfg80211_michael_mic_failure(priv->netdev, priv->cfg_bssid,
+ NL80211_KEYTYPE_PAIRWISE, -1, NULL,
+ GFP_KERNEL);
+ }
+#endif
break;
case MLAN_EVENT_ID_FW_MIC_ERR_MUL:
#ifdef STA_WEXT
@@ -961,18 +973,48 @@ moal_recv_event(IN t_void * pmoal_handle, IN pmlan_event pmevent)
#endif
}
#endif /* STA_WEXT */
+#ifdef STA_CFG80211
+ if (IS_STA_CFG80211(cfg80211_wext)) {
+ cfg80211_michael_mic_failure(priv->netdev, priv->cfg_bssid,
+ NL80211_KEYTYPE_GROUP, -1, NULL,
+ GFP_KERNEL);
+ }
+#endif
break;
case MLAN_EVENT_ID_FW_BCN_RSSI_LOW:
#ifdef STA_WEXT
if (IS_STA_WEXT(cfg80211_wext))
woal_send_iwevcustom_event(priv, CUS_EVT_BEACON_RSSI_LOW);
#endif
+#ifdef STA_CFG80211
+ if (IS_STA_CFG80211(cfg80211_wext)) {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) || defined(COMPAT_WIRELESS)
+ cfg80211_cqm_rssi_notify(priv->netdev,
+ NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
+ GFP_KERNEL);
+ priv->rssi_status = MLAN_EVENT_ID_FW_BCN_RSSI_LOW;
+#endif
+ woal_set_rssi_threshold(priv, MLAN_EVENT_ID_FW_BCN_RSSI_LOW);
+ }
+#endif
break;
case MLAN_EVENT_ID_FW_BCN_RSSI_HIGH:
#ifdef STA_WEXT
if (IS_STA_WEXT(cfg80211_wext))
woal_send_iwevcustom_event(priv, CUS_EVT_BEACON_RSSI_HIGH);
#endif
+#ifdef STA_CFG80211
+ if (IS_STA_CFG80211(cfg80211_wext)) {
+ if (!priv->mrvl_rssi_low) {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) || defined(COMPAT_WIRELESS)
+ cfg80211_cqm_rssi_notify(priv->netdev,
+ NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
+ GFP_KERNEL);
+#endif
+ woal_set_rssi_threshold(priv, MLAN_EVENT_ID_FW_BCN_RSSI_HIGH);
+ }
+ }
+#endif
break;
case MLAN_EVENT_ID_FW_BCN_SNR_LOW:
#ifdef STA_WEXT
@@ -1033,6 +1075,22 @@ moal_recv_event(IN t_void * pmoal_handle, IN pmlan_event pmevent)
if (IS_STA_WEXT(cfg80211_wext))
woal_send_iwevcustom_event(priv, CUS_EVT_PRE_BEACON_LOST);
#endif
+#ifdef STA_CFG80211
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) || defined(COMPAT_WIRELESS)
+ if (IS_STA_CFG80211(cfg80211_wext)) {
+ struct cfg80211_bss *bss = NULL;
+ bss =
+ cfg80211_get_bss(priv->wdev->wiphy, NULL, priv->cfg_bssid, NULL,
+ 0, WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
+ if (bss)
+ cfg80211_unlink_bss(priv->wdev->wiphy, bss);
+ cfg80211_cqm_rssi_notify(priv->netdev,
+ NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
+ GFP_KERNEL);
+ priv->rssi_status = MLAN_EVENT_ID_FW_PRE_BCN_LOST;
+ }
+#endif
+#endif
break;
case MLAN_EVENT_ID_FW_WMM_CONFIG_CHANGE:
#ifdef STA_WEXT
@@ -1069,11 +1127,22 @@ moal_recv_event(IN t_void * pmoal_handle, IN pmlan_event pmevent)
priv->bg_scan_reported = MTRUE;
#ifdef STA_WEXT
if (IS_STA_WEXT(cfg80211_wext)) {
- woal_send_iwevcustom_event(priv, CUS_EVT_BG_SCAN);
memset(&wrqu, 0, sizeof(union iwreq_data));
wireless_send_event(priv->netdev, SIOCGIWSCAN, &wrqu, NULL);
}
#endif
+#ifdef STA_CFG80211
+ if (IS_STA_CFG80211(cfg80211_wext)) {
+ woal_inform_bss_from_scan_result(priv, NULL);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) || defined(COMPAT_WIRELESS)
+ if (priv->mrvl_rssi_low) {
+ cfg80211_cqm_rssi_notify(priv->netdev,
+ NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
+ GFP_KERNEL);
+ }
+#endif
+ }
+#endif
break;
case MLAN_EVENT_ID_FW_CHANNEL_SWITCH_ANN:
#ifdef STA_WEXT
@@ -1285,10 +1354,15 @@ moal_recv_event(IN t_void * pmoal_handle, IN pmlan_event pmevent)
#endif /* UAP_WEXT */
break;
case MLAN_EVENT_ID_DRV_MGMT_FRAME:
+#ifdef UAP_WEXT
+ if (IS_UAP_WEXT(cfg80211_wext)) {
+ woal_broadcast_event(priv, pmevent->event_buf, pmevent->event_len);
+ }
+#endif /* UAP_WEXT */
#ifdef WIFI_DIRECT_SUPPORT
#if defined(STA_CFG80211) || defined(UAP_CFG80211)
if (IS_STA_OR_UAP_CFG80211(cfg80211_wext)) {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) || defined(COMPAT_WIRELESS)
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
if (priv->netdev && priv->netdev->ieee80211_ptr->wiphy->mgmt_stypes) {
/* frmctl + durationid + addr1 + addr2 + addr3 + seqctl */
#define PACKET_ADDR4_POS (2 + 2 + 6 + 6 + 6 + 2)
@@ -1310,11 +1384,6 @@ moal_recv_event(IN t_void * pmoal_handle, IN pmlan_event pmevent)
}
#endif /* STA_CFG80211 || UAP_CFG80211 */
#endif /* WIFI_DIRECT_SUPPORT */
-#ifdef UAP_WEXT
- if (IS_UAP_WEXT(cfg80211_wext)) {
- woal_broadcast_event(priv, pmevent->event_buf, pmevent->event_len);
- }
-#endif /* UAP_WEXT */
break;
#endif /* UAP_SUPPORT */
case MLAN_EVENT_ID_DRV_PASSTHRU:
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.c b/drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.c
index d6768a3bd647..8a60be2298c8 100644
--- a/drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.c
+++ b/drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.c
@@ -44,6 +44,11 @@ static int woal_cfg80211_dump_station(struct wiphy *wiphy,
static int woal_cfg80211_set_power_mgmt(struct wiphy *wiphy,
struct net_device *dev, bool enabled,
int timeout);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) || defined(COMPAT_WIRELESS)
+static int woal_cfg80211_set_cqm_rssi_config(struct wiphy *wiphy,
+ struct net_device *dev,
+ s32 rssi_thold, u32 rssi_hyst);
+#endif
static int woal_cfg80211_set_tx_power(struct wiphy *wiphy,
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) && !defined(COMPAT_WIRELESS)
@@ -98,6 +103,9 @@ static struct cfg80211_ops woal_cfg80211_sta_ops = {
.set_default_key = woal_cfg80211_set_default_key,
.set_power_mgmt = woal_cfg80211_set_power_mgmt,
.set_tx_power = woal_cfg80211_set_tx_power,
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) || defined(COMPAT_WIRELESS)
+ .set_cqm_rssi_config = woal_cfg80211_set_cqm_rssi_config,
+#endif
};
#if defined(WIFI_DIRECT_SUPPORT)
@@ -518,14 +526,13 @@ woal_cfg80211_assoc_ies_cfg(moal_private * priv, t_u8 * ie, int ie_len)
/**
* @brief Send domain info command to FW
*
- * @param wiphy A pointer to wiphy structure
+ * @param priv A pointer to moal_private structure
*
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
static mlan_status
-woal_send_domain_info_cmd_fw(struct wiphy *wiphy)
+woal_send_domain_info_cmd_fw(moal_private * priv)
{
- moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
mlan_status ret = MLAN_STATUS_SUCCESS;
enum ieee80211_band band;
struct ieee80211_supported_band *sband = NULL;
@@ -540,6 +547,12 @@ woal_send_domain_info_cmd_fw(struct wiphy *wiphy)
ENTER();
+ if (!priv->wdev || !priv->wdev->wiphy) {
+ PRINTM(MERROR, "No wdev or wiphy in priv\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
/* Allocate an IOCTL request buffer */
req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
if (req == NULL) {
@@ -556,7 +569,7 @@ woal_send_domain_info_cmd_fw(struct wiphy *wiphy)
goto done;
}
band = woal_band_cfg_to_ieee_band(radio_cfg->param.band_cfg.config_bands);
- if (!wiphy->bands[band]) {
+ if (!priv->wdev->wiphy->bands[band]) {
PRINTM(MERROR, "11D: setting domain info in FW failed");
ret = MLAN_STATUS_FAILURE;
goto done;
@@ -580,7 +593,7 @@ woal_send_domain_info_cmd_fw(struct wiphy *wiphy)
cfg_11d->param.domain_info.country_code[2] = ' ';
cfg_11d->param.domain_info.band = band;
- sband = wiphy->bands[band];
+ sband = priv->wdev->wiphy->bands[band];
for (i = 0; (i < sband->n_channels) &&
(no_of_sub_band < MRVDRV_MAX_SUBBAND_802_11D); i++) {
channel = &sband->channels[i];
@@ -641,18 +654,17 @@ woal_send_domain_info_cmd_fw(struct wiphy *wiphy)
* @brief Request the driver to change the channel and
* change domain info according to that channel
*
- * @param wiphy A pointer to wiphy structure
+ * @param priv A pointer to moal_private structure
* @param chan A pointer to ieee80211_channel structure
* @param channel_type Channel type of nl80211_channel_type
*
* @return 0 -- success, otherwise fail
*/
int
-woal_set_rf_channel(struct wiphy *wiphy,
+woal_set_rf_channel(moal_private * priv,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type)
{
- moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
int ret = 0;
t_u32 mode, config_bands = 0;
mlan_ioctl_req *req1 = NULL, *req2 = NULL;
@@ -692,7 +704,7 @@ woal_set_rf_channel(struct wiphy *wiphy,
ret = -EFAULT;
goto done;
}
- woal_send_domain_info_cmd_fw(wiphy);
+ woal_send_domain_info_cmd_fw(priv);
}
PRINTM(MINFO, "Setting band %d, channel bandwidth %d and mode = %d\n",
@@ -864,17 +876,15 @@ woal_inform_bss_from_scan_result(moal_private * priv, mlan_802_11_ssid * ssid)
struct ieee80211_channel *chan;
mlan_scan_resp scan_resp;
BSSDescriptor_t *scan_table;
- t_u8 *ie, *tmp, *ie_buf;
- __le32 ie_len;
t_u64 ts = 0;
- t_u8 *cap;
- t_u8 *beacon;
- int beacon_size, i, j;
- IEEEtypes_ElementId_e element_id;
- t_u8 element_len;
+ u16 cap_info = 0;
+ int i = 0;
struct cfg80211_bss *pub = NULL;
-
ENTER();
+ if (!priv->wdev || !priv->wdev->wiphy) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
memset(&scan_resp, 0, sizeof(scan_resp));
if (MLAN_STATUS_SUCCESS != woal_get_scan_table(priv,
@@ -885,14 +895,6 @@ woal_inform_bss_from_scan_result(moal_private * priv, mlan_802_11_ssid * ssid)
}
if (scan_resp.num_in_scan_table) {
-#define MAX_IE_BUF 2048
- ie_buf = kzalloc(MAX_IE_BUF, GFP_KERNEL);
- if (ie_buf == NULL) {
- PRINTM(MERROR, "%s: failed to allocate ie_buf\n", __func__);
- ret = MLAN_STATUS_FAILURE;
- goto done;
- }
-
scan_table = (BSSDescriptor_t *) scan_resp.pscan_table;
for (i = 0; i < scan_resp.num_in_scan_table; i++) {
if (ssid) {
@@ -905,105 +907,31 @@ woal_inform_bss_from_scan_result(moal_private * priv, mlan_802_11_ssid * ssid)
(int) scan_table[i].channel);
continue;
}
- memset(ie_buf, 0, MAX_IE_BUF);
- ie_buf[0] = WLAN_EID_SSID;
- ie_buf[1] = scan_table[i].ssid.ssid_len;
- memcpy(&ie_buf[sizeof(IEEEtypes_Header_t)],
- scan_table[i].ssid.ssid, ie_buf[1]);
-
- ie = ie_buf + ie_buf[1] + sizeof(IEEEtypes_Header_t);
- ie_len = ie_buf[1] + sizeof(IEEEtypes_Header_t);
-
- ie[0] = WLAN_EID_SUPP_RATES;
-
- for (j = 0; j < sizeof(scan_table[i].supported_rates); j++) {
- if (!scan_table[i].supported_rates[j])
- break;
- else {
- ie[j + sizeof(IEEEtypes_Header_t)] =
- scan_table[i].supported_rates[j];
- }
- }
-
- ie[1] = j;
- ie_len += ie[1] + sizeof(IEEEtypes_Header_t);
-
- beacon = scan_table[i].pbeacon_buf;
- beacon_size = scan_table[i].beacon_buf_size;
-
- /* Skip time stamp, beacon interval and capability */
-
- if (beacon) {
- beacon += sizeof(scan_table[i].beacon_period)
- + sizeof(scan_table[i].time_stamp) +
- +sizeof(scan_table[i].cap_info);
-
- beacon_size -= sizeof(scan_table[i].beacon_period)
- + sizeof(scan_table[i].time_stamp)
- + sizeof(scan_table[i].cap_info);
- }
-
- while (beacon_size >= sizeof(IEEEtypes_Header_t)) {
- ie = ie_buf + ie_len;
- element_id = *beacon;
- element_len = *(beacon + 1);
- if (beacon_size < (int) element_len +
- sizeof(IEEEtypes_Header_t)) {
- PRINTM(MERROR,
- "Get scan: Error in processing IE, "
- "bytes left < IE length\n");
- break;
- }
- switch (element_id) {
- case WLAN_EID_FH_PARAMS:
- case WLAN_EID_DS_PARAMS:
- case WLAN_EID_CF_PARAMS:
- case WLAN_EID_IBSS_PARAMS:
- case WLAN_EID_COUNTRY:
- case WLAN_EID_PWR_CONSTRAINT:
- case WLAN_EID_PWR_CAPABILITY:
- case WLAN_EID_TPC_REQUEST:
- case WLAN_EID_TPC_REPORT:
- case WLAN_EID_CHANNEL_SWITCH:
- case WLAN_EID_QUIET:
- case WLAN_EID_IBSS_DFS:
- case WLAN_EID_SUPPORTED_CHANNELS:
- case WLAN_EID_ERP_INFO:
- case WLAN_EID_EXT_SUPP_RATES:
- case WLAN_EID_HT_CAPABILITY:
- case WLAN_EID_HT_INFORMATION:
- case EXT_CAPABILITY: // TODO: Replace when kernel macro
- // available
- case WLAN_EID_RSN:
- case WAPI_IE: // TODO: Replace when kernel macro available
- case WLAN_EID_VENDOR_SPECIFIC:
- ie[0] = element_id;
- ie[1] = element_len;
- tmp = (t_u8 *) beacon;
- memcpy(&ie[sizeof(IEEEtypes_Header_t)],
- tmp + sizeof(IEEEtypes_Header_t), element_len);
- ie_len += ie[1] + sizeof(IEEEtypes_Header_t);
- break;
- default:
- break;
- }
- beacon += element_len + sizeof(IEEEtypes_Header_t);
- beacon_size -= (element_len + sizeof(IEEEtypes_Header_t));
- }
chan = ieee80211_get_channel(priv->wdev->wiphy, scan_table[i].freq);
- cap = (t_u8 *) & scan_table[i].cap_info;
+ if (!chan) {
+ PRINTM(MERROR,
+ "Fail to get chan with freq: channel=%d freq=%d\n",
+ (int) scan_table[i].channel, (int) scan_table[i].freq);
+ continue;
+ }
+ memcpy(&ts, scan_table[i].time_stamp, sizeof(ts));
+ memcpy(&cap_info, &scan_table[i].cap_info, sizeof(cap_info));
pub = cfg80211_inform_bss(priv->wdev->wiphy, chan,
scan_table[i].mac_address,
- ts, (__le16) (*cap),
- scan_table[i].beacon_period, ie_buf,
- ie_len,
+ ts, cap_info,
+ scan_table[i].beacon_period,
+ scan_table[i].pbeacon_buf +
+ WLAN_802_11_FIXED_IE_SIZE,
+ scan_table[i].beacon_buf_size -
+ WLAN_802_11_FIXED_IE_SIZE,
-RSSI_DBM_TO_MDM(scan_table[i].rssi),
GFP_KERNEL);
- pub->len_information_elements = pub->len_beacon_ies;
+ if (pub) {
+ pub->len_information_elements = pub->len_beacon_ies;
+ cfg80211_put_bss(pub);
+ }
}
- kfree(ie_buf);
}
-
done:
LEAVE();
return ret;
@@ -1044,6 +972,7 @@ woal_cfg80211_inform_ibss_bss(moal_private * priv,
mlan_ds_get_signal signal;
t_u8 ie_buf[MLAN_MAX_SSID_LENGTH + sizeof(IEEEtypes_Header_t)];
int ie_len = 0;
+ struct cfg80211_bss *bss = NULL;
ENTER();
@@ -1068,11 +997,12 @@ woal_cfg80211_inform_ibss_bss(moal_private * priv,
goto done;
}
- cfg80211_inform_bss(priv->wdev->wiphy, chan,
- bss_info.bssid, 0, WLAN_CAPABILITY_IBSS,
- beacon_interval, ie_buf, ie_len, signal.bcn_rssi_avg,
- GFP_KERNEL);
-
+ bss = cfg80211_inform_bss(priv->wdev->wiphy, chan,
+ bss_info.bssid, 0, WLAN_CAPABILITY_IBSS,
+ beacon_interval, ie_buf, ie_len,
+ signal.bcn_rssi_avg, GFP_KERNEL);
+ if (bss)
+ cfg80211_put_bss(bss);
done:
LEAVE();
return ret;
@@ -1081,15 +1011,14 @@ woal_cfg80211_inform_ibss_bss(moal_private * priv,
/**
* @brief Request the driver for (re)association
*
- * @param wiphy A pointer to wiphy structure
+ * @param priv A pointer to moal_private structure
* @param sme A pointer to connect parameters
*
* @return 0 -- success, otherwise fail
*/
static int
-woal_cfg80211_assoc(struct wiphy *wiphy, void *sme)
+woal_cfg80211_assoc(moal_private * priv, void *sme)
{
- moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
struct cfg80211_ibss_params *ibss_param = NULL;
struct cfg80211_connect_params *conn_param = NULL;
mlan_802_11_ssid req_ssid;
@@ -1153,7 +1082,7 @@ woal_cfg80211_assoc(struct wiphy *wiphy, void *sme)
goto done;
}
- if (channel) {
+ if (mode == MLAN_BSS_MODE_IBSS && channel) {
/* Get the secondary channel offset */
req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
if (req == NULL) {
@@ -1170,7 +1099,7 @@ woal_cfg80211_assoc(struct wiphy *wiphy, void *sme)
ret = -EFAULT;
goto done;
}
- if (MLAN_STATUS_SUCCESS != woal_set_rf_channel(wiphy,
+ if (MLAN_STATUS_SUCCESS != woal_set_rf_channel(priv,
channel,
woal_channel_to_nl80211_channel_type
(radio_cfg->param.
@@ -1188,8 +1117,9 @@ woal_cfg80211_assoc(struct wiphy *wiphy, void *sme)
}
if (MLAN_STATUS_SUCCESS !=
- woal_cfg80211_set_key(priv, 0, 0, NULL, 0, NULL, 0, 0, NULL, 1)) {
- /* Disable keys */
+ woal_cfg80211_set_key(priv, 0, 0, NULL, 0, NULL, 0,
+ KEY_INDEX_CLEAR_ALL, NULL, 1)) {
+ /* Disable keys and clear all previous security settings */
ret = -EFAULT;
goto done;
}
@@ -1386,6 +1316,58 @@ woal_cfg80211_assoc(struct wiphy *wiphy, void *sme)
return ret;
}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) || defined(COMPAT_WIRELESS)
+/**
+ * @brief Set/Get DTIM period
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action set or get
+ * @param wait_option Wait option
+ * @param value DTIM period
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+static mlan_status
+woal_set_get_dtim_period(moal_private * priv,
+ t_u32 action, t_u8 wait_option, t_u8 * value)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_snmp_mib *mib = NULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_snmp_mib));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ mib = (mlan_ds_snmp_mib *) req->pbuf;
+ mib->sub_command = MLAN_OID_SNMP_MIB_DTIM_PERIOD;
+ req->req_id = MLAN_IOCTL_SNMP_MIB;
+ req->action = action;
+
+ if (action == MLAN_ACT_SET) {
+ mib->param.dtim_period = *value;
+ }
+
+ /* Send IOCTL request to MLAN */
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret == MLAN_STATUS_SUCCESS && action == MLAN_ACT_GET) {
+ *value = (t_u8) mib->param.dtim_period;
+ }
+
+ done:
+ if (req && (ret != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+#endif
+
/**
* @brief Request the driver to dump the station information
*
@@ -1397,10 +1379,14 @@ woal_cfg80211_assoc(struct wiphy *wiphy, void *sme)
static mlan_status
woal_cfg80211_dump_station_info(moal_private * priv, struct station_info *sinfo)
{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_ds_get_signal signal;
mlan_ioctl_req *req = NULL;
mlan_ds_rate *rate = NULL;
- mlan_status ret = MLAN_STATUS_SUCCESS;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) || defined(COMPAT_WIRELESS)
+ mlan_bss_info bss_info;
+ t_u8 dtim_period = 0;
+#endif
ENTER();
sinfo->filled = STATION_INFO_RX_BYTES | STATION_INFO_TX_BYTES |
@@ -1443,6 +1429,28 @@ woal_cfg80211_dump_station_info(moal_private * priv, struct station_info *sinfo)
sinfo->tx_packets = priv->stats.tx_packets;
sinfo->signal = signal.bcn_rssi_avg;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) || defined(COMPAT_WIRELESS)
+ /* Update BSS information */
+ sinfo->filled |= STATION_INFO_BSS_PARAM;
+ sinfo->bss_param.flags = 0;
+ ret = woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+ if (ret)
+ goto done;
+ if (bss_info.capability_info & WLAN_CAPABILITY_SHORT_PREAMBLE)
+ sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE;
+ if (bss_info.capability_info & WLAN_CAPABILITY_SHORT_SLOT_TIME)
+ sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME;
+ sinfo->bss_param.beacon_interval = bss_info.beacon_interval;
+ /* Get DTIM period */
+ ret = woal_set_get_dtim_period(priv, MLAN_ACT_GET,
+ MOAL_IOCTL_WAIT, &dtim_period);
+ if (ret) {
+ PRINTM(MERROR, "Get DTIM period failed\n");
+ goto done;
+ }
+ sinfo->bss_param.dtim_period = dtim_period;
+#endif
+
done:
if (req)
kfree(req);
@@ -1472,6 +1480,12 @@ woal_cfg80211_reg_notifier(struct wiphy *wiphy,
ENTER();
+ if (!priv) {
+ PRINTM(MFATAL, "Unable to get priv in %s()\n", __FUNCTION__);
+ LEAVE();
+ return -EINVAL;
+ }
+
PRINTM(MINFO, "cfg80211 regulatory domain callback "
"%c%c\n", request->alpha2[0], request->alpha2[1]);
@@ -1496,7 +1510,7 @@ woal_cfg80211_reg_notifier(struct wiphy *wiphy,
break;
}
- if (MLAN_STATUS_SUCCESS != woal_send_domain_info_cmd_fw(wiphy))
+ if (MLAN_STATUS_SUCCESS != woal_send_domain_info_cmd_fw(priv))
ret = -EFAULT;
LEAVE();
@@ -1519,7 +1533,7 @@ static int
woal_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_scan_request *request)
{
- moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(dev);
wlan_user_scan_cfg scan_req;
struct ieee80211_channel *chan;
int ret = 0, i;
@@ -1604,10 +1618,11 @@ static int
woal_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_connect_params *sme)
{
- moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(dev);
int ret = 0;
ENTER();
+
PRINTM(MINFO, "Received association request on %s\n", dev->name);
if (priv->wdev->iftype != NL80211_IFTYPE_STATION
@@ -1645,7 +1660,7 @@ woal_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE);
- ret = woal_cfg80211_assoc(wiphy, (void *) sme);
+ ret = woal_cfg80211_assoc(priv, (void *) sme);
if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE);
@@ -1680,7 +1695,7 @@ static int
woal_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
t_u16 reason_code)
{
- moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(dev);
ENTER();
PRINTM(MINFO, "Received disassociation request on %s\n", dev->name);
@@ -1729,7 +1744,7 @@ woal_cfg80211_get_station(struct wiphy *wiphy,
t_u8 * mac, struct station_info *sinfo)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
- moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(dev);
ENTER();
@@ -1778,7 +1793,7 @@ woal_cfg80211_dump_station(struct wiphy *wiphy,
t_u8 * mac, struct station_info *sinfo)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
- moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(dev);
ENTER();
@@ -1814,7 +1829,7 @@ static int
woal_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_ibss_params *params)
{
- moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(dev);
int ret = 0;
ENTER();
@@ -1826,7 +1841,7 @@ woal_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
return -EINVAL;
}
- ret = woal_cfg80211_assoc(wiphy, (void *) params);
+ ret = woal_cfg80211_assoc(priv, (void *) params);
if (!ret) {
cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid, GFP_KERNEL);
@@ -1852,7 +1867,7 @@ woal_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
static int
woal_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
{
- moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(dev);
ENTER();
@@ -1898,7 +1913,7 @@ woal_cfg80211_set_power_mgmt(struct wiphy *wiphy,
struct net_device *dev, bool enabled, int timeout)
{
int ret = 0, disabled;
- moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(dev);
ENTER();
@@ -1940,6 +1955,12 @@ woal_cfg80211_set_tx_power(struct wiphy *wiphy,
ENTER();
+ if (!priv) {
+ PRINTM(MFATAL, "Unable to get priv in %s()\n", __FUNCTION__);
+ LEAVE();
+ return -EFAULT;
+ }
+
if (type) {
power_cfg.is_power_auto = 0;
power_cfg.power_level = dbm;
@@ -1954,6 +1975,33 @@ woal_cfg80211_set_tx_power(struct wiphy *wiphy,
return ret;
}
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) || defined(COMPAT_WIRELESS)
+/**
+ * CFG802.11 operation handler for connection quality monitoring.
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param rssi_thold rssi threshold
+ * @param rssi_hyst rssi hysteresis
+ */
+static int
+woal_cfg80211_set_cqm_rssi_config(struct wiphy *wiphy,
+ struct net_device *dev,
+ s32 rssi_thold, u32 rssi_hyst)
+{
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(dev);
+ ENTER();
+ priv->cqm_rssi_thold = rssi_thold;
+ priv->cqm_rssi_hyst = rssi_hyst;
+
+ PRINTM(MIOCTL, "rssi_thold=%d rssi_hyst=%d\n",
+ (int) rssi_thold, (int) rssi_hyst);
+ woal_set_rssi_threshold(priv, 0);
+ LEAVE();
+ return 0;
+}
+#endif
+
/**
* @brief Sets up the CFG802.11 specific HT capability fields
* with default values
@@ -2010,7 +2058,7 @@ woal_cfg80211_setup_sta_ht_cap(struct ieee80211_sta_ht_cap *ht_info,
/**
* @brief remain on channel config
*
- * @param wiphy A pointer to wiphy structure
+ * @param priv A pointer to moal_private structure
* @param wait_option Wait option
* @param cancel cancel remain on channel flag
* @param status A pointer to status, success, in process or reject
@@ -2021,7 +2069,7 @@ woal_cfg80211_setup_sta_ht_cap(struct ieee80211_sta_ht_cap *ht_info,
* @return 0 -- success, otherwise fail
*/
int
-woal_cfg80211_remain_on_channel_cfg(struct wiphy *wiphy,
+woal_cfg80211_remain_on_channel_cfg(moal_private * priv,
t_u8 wait_option, t_u8 remove,
t_u8 * status,
struct ieee80211_channel *chan,
@@ -2029,8 +2077,6 @@ woal_cfg80211_remain_on_channel_cfg(struct wiphy *wiphy,
t_u32 duration)
{
mlan_ds_remain_chan chan_cfg;
- moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
-
int ret = 0;
ENTER();
@@ -2042,10 +2088,6 @@ woal_cfg80211_remain_on_channel_cfg(struct wiphy *wiphy,
chan_cfg.bandcfg = 0;
else if (chan->band == IEEE80211_BAND_5GHZ)
chan_cfg.bandcfg = 1;
-/** secondary channel is below */
-#define SEC_CHAN_BELOW 0x30
-/** secondary channel is above */
-#define SEC_CHAN_ABOVE 0x10
switch (channel_type) {
case NL80211_CHAN_HT40MINUS:
chan_cfg.bandcfg |= SEC_CHANNEL_BELOW;
@@ -2084,14 +2126,14 @@ static int
woal_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
struct net_device *dev, u64 cookie)
{
- moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(dev);
int ret = 0;
t_u8 status = 1;
ENTER();
if (priv->phandle->remain_on_channel) {
- if (woal_cfg80211_remain_on_channel_cfg(priv->wdev->wiphy,
+ if (woal_cfg80211_remain_on_channel_cfg(priv,
MOAL_IOCTL_WAIT, MTRUE, &status,
NULL, 0, 0)) {
PRINTM(MERROR, "Fail to cancel remain on channel\n");
@@ -2133,7 +2175,7 @@ woal_cfg80211_remain_on_channel(struct wiphy *wiphy,
enum nl80211_channel_type channel_type,
unsigned int duration, u64 * cookie)
{
- moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(dev);
int ret = 0;
t_u8 status = 1;
@@ -2146,8 +2188,9 @@ woal_cfg80211_remain_on_channel(struct wiphy *wiphy,
}
/** cancel previous remain on channel */
if (priv->phandle->remain_on_channel) {
- if (woal_cfg80211_remain_on_channel_cfg
- (wiphy, MOAL_IOCTL_WAIT, MTRUE, &status, NULL, 0, 0)) {
+ if (woal_cfg80211_remain_on_channel_cfg(priv,
+ MOAL_IOCTL_WAIT, MTRUE, &status,
+ NULL, 0, 0)) {
PRINTM(MERROR, "Fail to cancel remain on channel\n");
ret = -EFAULT;
goto done;
@@ -2156,7 +2199,7 @@ woal_cfg80211_remain_on_channel(struct wiphy *wiphy,
priv->phandle->remain_on_channel = MFALSE;
}
if (MLAN_STATUS_SUCCESS !=
- woal_cfg80211_remain_on_channel_cfg(wiphy, MOAL_IOCTL_WAIT,
+ woal_cfg80211_remain_on_channel_cfg(priv, MOAL_IOCTL_WAIT,
MFALSE, &status, chan, channel_type,
(t_u32) duration)) {
ret = -EFAULT;
@@ -2195,14 +2238,15 @@ static int
woal_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
struct net_device *dev, u64 cookie)
{
- moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(dev);
int ret = 0;
t_u8 status = 1;
ENTER();
PRINTM(MIOCTL, "Cancel remain on Channel: cookie = %#llx\n", cookie);
- if (woal_cfg80211_remain_on_channel_cfg
- (wiphy, MOAL_IOCTL_WAIT, MTRUE, &status, NULL, 0, 0)) {
+ if (woal_cfg80211_remain_on_channel_cfg(priv,
+ MOAL_IOCTL_WAIT, MTRUE, &status,
+ NULL, 0, 0)) {
PRINTM(MERROR, "Fail to cancel remain on channel\n");
ret = -EFAULT;
goto done;
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_uap_cfg80211.c b/drivers/net/wireless/sd8797/mlinux/moal_uap_cfg80211.c
index 7f7528216282..18d18328d0ed 100644
--- a/drivers/net/wireless/sd8797/mlinux/moal_uap_cfg80211.c
+++ b/drivers/net/wireless/sd8797/mlinux/moal_uap_cfg80211.c
@@ -124,44 +124,6 @@ static struct cfg80211_ops woal_cfg80211_uap_ops = {
/********************************************************
Global Functions
********************************************************/
-/**
- * @brief Filter specific IE in ie buf
- *
- * @param ie Pointer to IEs
- * @param len Total length of ie
- * @param ie_out Pointer to out IE buf
- *
- * @return out IE length
- */
-static t_u16
-woal_filter_beacon_ies(const t_u8 * ie, int len, t_u8 * ie_out)
-{
- int left_len = len;
- const t_u8 *pos = ie;
- int length;
- t_u8 id = 0;
- t_u16 out_len = 0;
-
- /* ERP_INFO and RSN IE will be fileter out */
- while (left_len >= 2) {
- length = *(pos + 1);
- id = *pos;
- if ((length + 2) > left_len)
- break;
- switch (id) {
- case ERP_INFO:
- case RSN_IE:
- break;
- default:
- memcpy(ie_out + out_len, pos, length + 2);
- out_len += length + 2;
- break;
- }
- pos += (length + 2);
- left_len -= (length + 2);
- }
- return out_len;
-}
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0) && !defined(COMPAT_WIRELESS)
/**
@@ -364,442 +326,6 @@ woal_find_wpa_ies(t_u8 * ie, int len, mlan_uap_bss_param * sys_config)
#endif
/**
- * @brief Look up specific IE in a buf
- *
- * @param ie Pointer to IEs
- * @param len Total length of ie
- * @param id Element id to lookup
- *
- * @return Pointer of the specific IE -- success, NULL -- fail
- */
-static const t_u8 *
-woal_parse_ie_tlv(const t_u8 * ie, int len, t_u8 id)
-{
- int left_len = len;
- const t_u8 *pos = ie;
- int length;
-
- /* IE format: | u8 | id | | u8 | len | | var | data | */
- while (left_len >= 2) {
- length = *(pos + 1);
- if ((*pos == id) && (length + 2) <= left_len)
- return pos;
- pos += (length + 2);
- left_len -= (length + 2);
- }
-
- return NULL;
-}
-
-/**
- * @brief Add custom ie to mgmt frames.
- *
- * @param priv A pointer to moal private structure
- * @param beacon_ies_data Beacon ie
- * @param beacon_index The index for beacon when auto index
- * @param proberesp_ies_data Probe resp ie
- * @param proberesp_index The index for probe resp when auto index
- * @param assocresp_ies_data Assoc resp ie
- * @param assocresp_index The index for assoc resp when auto index
- * @param probereq_ies_data Probe req ie
- * @param probereq_index The index for probe req when auto index *
- *
- * @return 0 -- success, otherwise fail
- */
-static int
-woal_cfg80211_custom_ie(moal_private * priv,
- custom_ie * beacon_ies_data, t_u16 * beacon_index,
- custom_ie * proberesp_ies_data, t_u16 * proberesp_index,
- custom_ie * assocresp_ies_data, t_u16 * assocresp_index,
- custom_ie * probereq_ies_data, t_u16 * probereq_index)
-{
- mlan_ioctl_req *ioctl_req = NULL;
- mlan_ds_misc_cfg *misc = NULL;
- mlan_ds_misc_custom_ie *custom_ie = NULL;
- t_u8 *pos = NULL;
- t_u16 len = 0;
- int ret = 0;
-
- ENTER();
-
- if (!(custom_ie = kmalloc(sizeof(mlan_ds_misc_custom_ie), GFP_KERNEL))) {
- ret = -ENOMEM;
- goto done;
- }
-
- memset(custom_ie, 0x00, sizeof(mlan_ds_misc_custom_ie));
- custom_ie->type = TLV_TYPE_MGMT_IE;
-
- pos = (t_u8 *) custom_ie->ie_data_list;
- if (beacon_ies_data) {
- len = sizeof(*beacon_ies_data) - MAX_IE_SIZE
- + beacon_ies_data->ie_length;
- memcpy(pos, beacon_ies_data, len);
- pos += len;
- custom_ie->len += len;
- }
-
- if (proberesp_ies_data) {
- len = sizeof(*proberesp_ies_data) - MAX_IE_SIZE
- + proberesp_ies_data->ie_length;
- memcpy(pos, proberesp_ies_data, len);
- pos += len;
- custom_ie->len += len;
- }
-
- if (assocresp_ies_data) {
- len = sizeof(*assocresp_ies_data) - MAX_IE_SIZE
- + assocresp_ies_data->ie_length;
- memcpy(pos, assocresp_ies_data, len);
- custom_ie->len += len;
- }
-
- if (probereq_ies_data) {
- len = sizeof(*probereq_ies_data) - MAX_IE_SIZE
- + probereq_ies_data->ie_length;
- memcpy(pos, probereq_ies_data, len);
- pos += len;
- custom_ie->len += len;
- }
-
- ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
- if (ioctl_req == NULL) {
- ret = -ENOMEM;
- goto done;
- }
-
- misc = (mlan_ds_misc_cfg *) ioctl_req->pbuf;
- misc->sub_command = MLAN_OID_MISC_CUSTOM_IE;
- ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
- ioctl_req->action = MLAN_ACT_SET;
-
- memcpy(&misc->param.cust_ie, custom_ie, sizeof(mlan_ds_misc_custom_ie));
-
- if (MLAN_STATUS_SUCCESS !=
- woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
- ret = -EFAULT;
- goto done;
- }
-
- /* get the assigned index */
- pos = (t_u8 *) (&misc->param.cust_ie.ie_data_list[0].ie_index);
- if (beacon_ies_data && beacon_ies_data->ie_length
- && beacon_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
- /* save beacon ie index after auto-indexing */
- *beacon_index = misc->param.cust_ie.ie_data_list[0].ie_index;
- len = sizeof(*beacon_ies_data) - MAX_IE_SIZE
- + beacon_ies_data->ie_length;
- pos += len;
- }
-
- if (proberesp_ies_data && proberesp_ies_data->ie_length
- && proberesp_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
- /* save probe resp ie index after auto-indexing */
- *proberesp_index = *((t_u16 *) pos);
- len = sizeof(*proberesp_ies_data) - MAX_IE_SIZE
- + proberesp_ies_data->ie_length;
- pos += len;
- }
-
- if (assocresp_ies_data && assocresp_ies_data->ie_length
- && assocresp_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
- /* save assoc resp ie index after auto-indexing */
- *assocresp_index = *((t_u16 *) pos);
- len = sizeof(*assocresp_ies_data) - MAX_IE_SIZE
- + assocresp_ies_data->ie_length;
- pos += len;
- }
- if (probereq_ies_data && probereq_ies_data->ie_length
- && probereq_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
- /* save probe resp ie index after auto-indexing */
- *probereq_index = *((t_u16 *) pos);
- len = sizeof(*probereq_ies_data) - MAX_IE_SIZE
- + probereq_ies_data->ie_length;
- pos += len;
- }
-
- if (ioctl_req->status_code == MLAN_ERROR_IOCTL_FAIL)
- ret = -EFAULT;
-
- done:
- if (ioctl_req)
- kfree(ioctl_req);
- if (custom_ie)
- kfree(custom_ie);
- LEAVE();
- return ret;
-}
-
-/**
- * @brief This function returns priv
- * based on mgmt ie index
- *
- * @param handle A pointer to moal_handle
- * @param index mgmt ie index
- *
- * @return Pointer to moal_private
- */
-static moal_private *
-woal_get_priv_by_mgmt_index(moal_handle * handle, t_u16 index)
-{
- int i;
-
- for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) {
- if (handle->priv[i]) {
- if (handle->priv[i]->probereq_index == index)
- return (handle->priv[i]);
- }
- }
- return NULL;
-}
-
-/**
- * @brief config AP or GO for mgmt frame ies.
- *
- * @param priv A pointer to moal private structure
- * @param beacon_ies A pointer to beacon ies
- * @param beacon_ies_len Beacon ies length
- * @param proberesp_ies A pointer to probe resp ies
- * @param proberesp_ies_len Probe resp ies length
- * @param assocresp_ies A pointer to probe resp ies
- * @param assocresp_ies_len Assoc resp ies length
- * @param probereq_ies A pointer to probe req ies
- * @param probereq_ies_len Probe req ies length *
- * @param mask Mgmt frame mask
- *
- * @return 0 -- success, otherwise fail
- */
-int
-woal_cfg80211_mgmt_frame_ie(moal_private * priv,
- const t_u8 * beacon_ies, size_t beacon_ies_len,
- const t_u8 * proberesp_ies,
- size_t proberesp_ies_len,
- const t_u8 * assocresp_ies,
- size_t assocresp_ies_len, const t_u8 * probereq_ies,
- size_t probereq_ies_len, t_u16 mask)
-{
- int ret = 0;
- t_u8 *pos = NULL;
- custom_ie *beacon_ies_data = NULL;
- custom_ie *proberesp_ies_data = NULL;
- custom_ie *assocresp_ies_data = NULL;
- custom_ie *probereq_ies_data = NULL;
-
- /* static variables for mgmt frame ie auto-indexing */
- static t_u16 beacon_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
- static t_u16 proberesp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
- static t_u16 assocresp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
- static t_u16 probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
- moal_private *pmpriv = NULL;
- static t_u16 rsn_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
- const t_u8 *rsn_ie;
-
- ENTER();
-
- if (mask & MGMT_MASK_BEACON) {
- if (!(beacon_ies_data = kmalloc(sizeof(custom_ie), GFP_KERNEL))) {
- ret = -ENOMEM;
- goto done;
- }
- if (beacon_ies && beacon_ies_len) {
- rsn_ie =
- woal_parse_ie_tlv((t_u8 *) beacon_ies, (int) beacon_ies_len,
- RSN_IE);
- if (rsn_ie) {
- beacon_ies_data->ie_index = rsn_index;
- beacon_ies_data->mgmt_subtype_mask =
- MGMT_MASK_BEACON | MGMT_MASK_PROBE_RESP |
- MGMT_MASK_ASSOC_RESP;
- beacon_ies_data->ie_length = rsn_ie[1] + 2;
- memcpy(beacon_ies_data->ie_buffer, rsn_ie, rsn_ie[1] + 2);
- if (MLAN_STATUS_SUCCESS !=
- woal_cfg80211_custom_ie(priv, beacon_ies_data, &rsn_index,
- NULL, &proberesp_index, NULL,
- &assocresp_index, NULL,
- &probereq_index)) {
- ret = -EFAULT;
- goto done;
- }
- }
- } else {
- /* clear rsn_ie */
- if (rsn_index <= MAX_MGMT_IE_INDEX) {
- beacon_ies_data->ie_index = rsn_index;
- beacon_ies_data->mgmt_subtype_mask = MLAN_CUSTOM_IE_DELETE_MASK;
- beacon_ies_data->ie_length = 0;
- rsn_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
- if (MLAN_STATUS_SUCCESS !=
- woal_cfg80211_custom_ie(priv, beacon_ies_data, &rsn_index,
- NULL, &proberesp_index, NULL,
- &assocresp_index, NULL,
- &probereq_index)) {
- ret = -EFAULT;
- goto done;
- }
- }
- }
- }
-
- if (mask & MGMT_MASK_PROBE_RESP) {
- if (!(proberesp_ies_data = kmalloc(sizeof(custom_ie), GFP_KERNEL))) {
- ret = -ENOMEM;
- goto done;
- }
- }
-
- if (mask & MGMT_MASK_ASSOC_RESP) {
- if (!(assocresp_ies_data = kmalloc(sizeof(custom_ie), GFP_KERNEL))) {
- ret = -ENOMEM;
- goto done;
- }
- }
- if (mask & MGMT_MASK_PROBE_REQ) {
- if (!(probereq_ies_data = kmalloc(sizeof(custom_ie), GFP_KERNEL))) {
- ret = -ENOMEM;
- goto done;
- }
- }
-
- if (beacon_ies_data) {
- memset(beacon_ies_data, 0x00, sizeof(custom_ie));
- if (beacon_ies && beacon_ies_len) {
- /* set the beacon ies */
- beacon_ies_data->ie_index = beacon_index;
- beacon_ies_data->mgmt_subtype_mask = MGMT_MASK_BEACON;
- beacon_ies_data->mgmt_subtype_mask |= MGMT_MASK_ASSOC_RESP;
- beacon_ies_data->ie_length = woal_filter_beacon_ies(beacon_ies,
- beacon_ies_len,
- beacon_ies_data->
- ie_buffer);
- } else {
- /* clear the beacon ies */
- if (beacon_index > MAX_MGMT_IE_INDEX) {
- PRINTM(MERROR, "Invalid beacon index for mgmt frame ie.\n");
- goto done;
- }
-
- beacon_ies_data->ie_index = beacon_index;
- beacon_ies_data->mgmt_subtype_mask = MLAN_CUSTOM_IE_DELETE_MASK;
- beacon_ies_data->ie_length = 0;
- beacon_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
- }
- }
-
- if (proberesp_ies_data) {
- memset(proberesp_ies_data, 0x00, sizeof(custom_ie));
- if (proberesp_ies && proberesp_ies_len) {
- /* set the probe response ies */
- // proberesp_ies_data->ie_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
- proberesp_ies_data->ie_index = proberesp_index;
- proberesp_ies_data->mgmt_subtype_mask = MGMT_MASK_PROBE_RESP;
- proberesp_ies_data->ie_length = proberesp_ies_len;
- pos = proberesp_ies_data->ie_buffer;
- memcpy(pos, proberesp_ies, proberesp_ies_len);
- } else {
- /* clear the probe response ies */
- if (proberesp_index > MAX_MGMT_IE_INDEX) {
- PRINTM(MERROR, "Invalid probe resp index for mgmt frame ie.\n");
- goto done;
- }
-
- proberesp_ies_data->ie_index = proberesp_index;
- proberesp_ies_data->mgmt_subtype_mask = MLAN_CUSTOM_IE_DELETE_MASK;
- proberesp_ies_data->ie_length = 0;
- proberesp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
- }
- }
- if (assocresp_ies_data) {
- memset(assocresp_ies_data, 0x00, sizeof(custom_ie));
- if (assocresp_ies && assocresp_ies_len) {
- /* set the assoc response ies */
- assocresp_ies_data->ie_index = assocresp_index;
- assocresp_ies_data->mgmt_subtype_mask = MGMT_MASK_ASSOC_RESP;
- assocresp_ies_data->ie_length = assocresp_ies_len;
- pos = assocresp_ies_data->ie_buffer;
- memcpy(pos, assocresp_ies, assocresp_ies_len);
- } else {
- /* clear the assoc response ies */
- if (assocresp_index > MAX_MGMT_IE_INDEX) {
- PRINTM(MERROR, "Invalid assoc resp index for mgmt frame ie.\n");
- goto done;
- }
-
- assocresp_ies_data->ie_index = assocresp_index;
- assocresp_ies_data->mgmt_subtype_mask = MLAN_CUSTOM_IE_DELETE_MASK;
- assocresp_ies_data->ie_length = 0;
- assocresp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
- }
- }
-
- if (probereq_ies_data) {
- memset(probereq_ies_data, 0x00, sizeof(custom_ie));
- if ((probereq_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK) &&
- (priv->probereq_index != probereq_index)) {
- pmpriv = woal_get_priv_by_mgmt_index(priv->phandle, probereq_index);
- if (pmpriv) {
- probereq_ies_data->ie_index = probereq_index;
- probereq_ies_data->mgmt_subtype_mask =
- MLAN_CUSTOM_IE_DELETE_MASK;
- probereq_ies_data->ie_length = 0;
- probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
- pmpriv->probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
- if (MLAN_STATUS_SUCCESS !=
- woal_cfg80211_custom_ie(pmpriv, NULL, &beacon_index,
- NULL, &proberesp_index,
- NULL, &assocresp_index,
- probereq_ies_data,
- &probereq_index)) {
- ret = -EFAULT;
- goto done;
- }
- memset(probereq_ies_data, 0x00, sizeof(custom_ie));
- }
- }
- if (probereq_ies && probereq_ies_len) {
- /* set the probe req ies */
- probereq_ies_data->ie_index = probereq_index;
- probereq_ies_data->mgmt_subtype_mask = MGMT_MASK_PROBE_REQ;
- probereq_ies_data->ie_length = probereq_ies_len;
- pos = probereq_ies_data->ie_buffer;
- memcpy(pos, probereq_ies, probereq_ies_len);
- } else {
- /* clear the probe req ies */
- if (probereq_index > MAX_MGMT_IE_INDEX) {
- PRINTM(MERROR, "Invalid probe resp index for mgmt frame ie.\n");
- goto done;
- }
- probereq_ies_data->ie_index = probereq_index;
- probereq_ies_data->mgmt_subtype_mask = MLAN_CUSTOM_IE_DELETE_MASK;
- probereq_ies_data->ie_length = 0;
- probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
- }
- }
-
- if (MLAN_STATUS_SUCCESS !=
- woal_cfg80211_custom_ie(priv, beacon_ies_data, &beacon_index,
- proberesp_ies_data, &proberesp_index,
- assocresp_ies_data, &assocresp_index,
- probereq_ies_data, &probereq_index)) {
- ret = -EFAULT;
- goto done;
- }
- if (probereq_ies_data)
- priv->probereq_index = probereq_index;
-
- done:
- if (beacon_ies_data)
- kfree(beacon_ies_data);
- if (proberesp_ies_data)
- kfree(proberesp_ies_data);
- if (assocresp_ies_data)
- kfree(assocresp_ies_data);
-
- LEAVE();
-
- return ret;
-}
-
-/**
* @brief initialize AP or GO bss config
*
* @param priv A pointer to moal private structure
@@ -1330,7 +856,7 @@ woal_cfg80211_add_beacon(struct wiphy *wiphy,
struct net_device *dev,
struct beacon_parameters *params)
{
- moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(dev);
int ret = 0;
ENTER();
@@ -1402,7 +928,7 @@ woal_cfg80211_set_beacon(struct wiphy *wiphy,
struct net_device *dev,
struct beacon_parameters *params)
{
- moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(dev);
int ret = 0;
ENTER();
@@ -1471,7 +997,7 @@ woal_cfg80211_set_beacon(struct wiphy *wiphy,
int
woal_cfg80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
{
- moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(dev);
int ret = 0;
ENTER();
@@ -1521,7 +1047,7 @@ int
woal_uap_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
u8 * mac, struct station_info *stainfo)
{
- moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ moal_private *priv = (moal_private *) woal_get_netdev_priv(dev);
int ret = -EFAULT;
int i = 0;
mlan_ds_get_info *info = NULL;
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_wext.c b/drivers/net/wireless/sd8797/mlinux/moal_wext.c
index 8595892090fb..a967c939f009 100644
--- a/drivers/net/wireless/sd8797/mlinux/moal_wext.c
+++ b/drivers/net/wireless/sd8797/mlinux/moal_wext.c
@@ -2124,12 +2124,14 @@ woal_set_priv(struct net_device *dev, struct iw_request_info *info,
priv->bg_scan_reported = MFALSE;
len = sprintf(buf, "OK\n") + 1;
} else if (strncmp(buf, "BGSCAN-STOP", strlen("BGSCAN-STOP")) == 0) {
- if (MLAN_STATUS_SUCCESS != woal_stop_bg_scan(priv)) {
- ret = -EFAULT;
- goto done;
+ if (priv->bg_scan_start && !priv->scan_cfg.rssi_threshold) {
+ if (MLAN_STATUS_SUCCESS != woal_stop_bg_scan(priv)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ priv->bg_scan_start = MFALSE;
+ priv->bg_scan_reported = MFALSE;
}
- priv->bg_scan_start = MFALSE;
- priv->bg_scan_reported = MFALSE;
len = sprintf(buf, "OK\n") + 1;
} else if (strncmp(buf, "RXFILTER-START", strlen("RXFILTER-START")) == 0) {
#ifdef MEF_CFG_RX_FILTER
@@ -2326,13 +2328,13 @@ woal_set_essid(struct net_device *dev, struct iw_request_info *info,
* Check if we asked for `any' or 'particular'
*/
if (!dwrq->flags) {
-
+#ifdef REASSOCIATION
if (!req_ssid.ssid_len) {
memset(&priv->prev_ssid_bssid.ssid, 0x00, sizeof(mlan_802_11_ssid));
memset(&priv->prev_ssid_bssid.bssid, 0x00, MLAN_MAC_ADDR_LENGTH);
goto setessid_ret;
}
-
+#endif
/* Do normal SSID scanning */
if (MLAN_STATUS_SUCCESS !=
woal_request_scan(priv, MOAL_IOCTL_WAIT, NULL)) {
@@ -2351,6 +2353,7 @@ woal_set_essid(struct net_device *dev, struct iw_request_info *info,
PRINTM(MINFO, "Requested new SSID = %s\n", (char *) req_ssid.ssid);
memcpy(&ssid_bssid.ssid, &req_ssid, sizeof(mlan_802_11_ssid));
+
if (dwrq->flags != 0xFFFF) {
if (MLAN_STATUS_SUCCESS != woal_find_essid(priv, &ssid_bssid)) {
/* Do specific SSID scanning */
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_wext.h b/drivers/net/wireless/sd8797/mlinux/moal_wext.h
index 91f918e1b130..dfafff866b96 100644
--- a/drivers/net/wireless/sd8797/mlinux/moal_wext.h
+++ b/drivers/net/wireless/sd8797/mlinux/moal_wext.h
@@ -45,7 +45,6 @@ Change log:
#define CUS_EVT_BEACON_SNR_HIGH "EVENT=BEACON_SNR_HIGH"
/** Custom event : Max fail */
#define CUS_EVT_MAX_FAIL "EVENT=MAX_FAIL"
-#define CUS_EVT_BG_SCAN "EVENT=BG_SCAN_REPORT"
/** Custom event : Data RSSI low */
#define CUS_EVT_DATA_RSSI_LOW "EVENT=DATA_RSSI_LOW"
/** Custom event : Data SNR low */
diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig
index dc29348264c6..c3706246a3b7 100644
--- a/drivers/pci/pcie/Kconfig
+++ b/drivers/pci/pcie/Kconfig
@@ -55,6 +55,31 @@ config PCIEASPM_DEBUG
This enables PCI Express ASPM debug support. It will add per-device
interface to control ASPM.
+choice
+ prompt "Default ASPM policy"
+ default PCIEASPM_DEFAULT
+ depends on PCIEASPM
+
+config PCIEASPM_DEFAULT
+ bool "BIOS default"
+ depends on PCIEASPM
+ help
+ Use the BIOS defaults for PCI Express ASPM.
+
+config PCIEASPM_POWERSAVE
+ bool "Powersave"
+ depends on PCIEASPM
+ help
+ Enable PCI Express ASPM L0s and L1 where possible, even if the
+ BIOS did not.
+
+config PCIEASPM_PERFORMANCE
+ bool "Performance"
+ depends on PCIEASPM
+ help
+ Disable PCI Express ASPM L0s and L1, even if the BIOS enabled them.
+endchoice
+
config PCIE_PME
def_bool y
depends on PCIEPORTBUS && PM_RUNTIME && EXPERIMENTAL && ACPI
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index cbfbab18be91..d65b56893506 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -76,7 +76,15 @@ static LIST_HEAD(link_list);
#define POLICY_DEFAULT 0 /* BIOS default setting */
#define POLICY_PERFORMANCE 1 /* high performance */
#define POLICY_POWERSAVE 2 /* high power saving */
+
+#ifdef CONFIG_PCIEASPM_PERFORMANCE
+static int aspm_policy = POLICY_PERFORMANCE;
+#elif defined CONFIG_PCIEASPM_POWERSAVE
+static int aspm_policy = POLICY_POWERSAVE;
+#else
static int aspm_policy;
+#endif
+
static const char *policy_str[] = {
[POLICY_DEFAULT] = "default",
[POLICY_PERFORMANCE] = "performance",
diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c
index e392f4dc77de..857deb8faa0a 100644
--- a/drivers/power/bq27x00_battery.c
+++ b/drivers/power/bq27x00_battery.c
@@ -885,6 +885,9 @@ static int bq27x00_battery_suspend(struct device *dev)
struct platform_device *pdev = to_platform_device(dev);
struct bq27x00_device_info *di = platform_get_drvdata(pdev);
+ cancel_delayed_work_sync(&di->work);
+ cancel_delayed_work_sync(&di->external_power_changed_work);
+
if (di->chip == BQ27510) {
ret = bq27x00_write(di, BQ27510_CNTL,
BQ27510_CNTL_SET_SLEEP, false);
@@ -920,6 +923,9 @@ static int bq27x00_battery_resume(struct device *dev)
return ret;
}
}
+
+ schedule_delayed_work(&di->work, HZ);
+
return 0;
}
diff --git a/drivers/power/smb349-charger.c b/drivers/power/smb349-charger.c
index 6164905efb70..134b8154a2b9 100644
--- a/drivers/power/smb349-charger.c
+++ b/drivers/power/smb349-charger.c
@@ -3,7 +3,7 @@
*
* Battery charger driver for smb349 from summit microelectronics
*
- * Copyright (c) 2012, NVIDIA Corporation.
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -36,6 +36,9 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/usb/otg.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/uaccess.h>
#define SMB349_CHARGE 0x00
#define SMB349_CHRG_CRNTS 0x01
@@ -170,17 +173,28 @@ static int smb349_configure_otg(struct i2c_client *client, int enable)
}
if (enable) {
- /* Configure PGOOD to be active low */
- ret = smb349_read(client, SMB349_SYSOK_USB3);
+ /* Configure PGOOD to be active low if no 5V on VBUS */
+ ret = smb349_read(client, SMB349_STS_REG_C);
if (ret < 0) {
dev_err(&client->dev, "%s: err %d\n", __func__, ret);
goto error;
}
- ret = smb349_write(client, SMB349_SYSOK_USB3, (ret & (~(1))));
- if (ret < 0) {
- dev_err(&client->dev, "%s: err %d\n", __func__, ret);
- goto error;
+ if (!(ret & 0x01)) {
+ ret = smb349_read(client, SMB349_SYSOK_USB3);
+ if (ret < 0) {
+ dev_err(&client->dev, "%s: err %d\n",
+ __func__, ret);
+ goto error;
+ }
+
+ ret = smb349_write(client, SMB349_SYSOK_USB3,
+ (ret & (~(1))));
+ if (ret < 0) {
+ dev_err(&client->dev, "%s: err %d\n",
+ __func__, ret);
+ goto error;
+ }
}
/* Enable OTG */
@@ -275,7 +289,7 @@ error:
int update_charger_status(void)
{
struct i2c_client *client;
- int ret, val;
+ int val;
if (!charger)
return -ENODEV;
@@ -304,8 +318,6 @@ int update_charger_status(void)
return 0;
val_error:
return val;
-ret_error:
- return ret;
}
EXPORT_SYMBOL_GPL(update_charger_status);
@@ -338,39 +350,53 @@ int smb349_battery_online(void)
return 1;
}
-static void smb349_otg_status(enum usb_otg_state to, enum usb_otg_state from, void *data)
+static int smb349_enable_otg(struct regulator_dev *otg_rdev)
{
struct i2c_client *client = charger->client;
int ret;
- if ((from == OTG_STATE_A_SUSPEND) && (to == OTG_STATE_A_HOST)) {
+ /* configure charger */
+ ret = smb349_configure_charger(client, 0);
+ if (ret < 0)
+ goto error;
+ /* ENABLE OTG */
+ ret = smb349_configure_otg(client, 1);
+ if (ret < 0)
+ goto error;
- /* configure charger */
- ret = smb349_configure_charger(client, 0);
- if (ret < 0)
- dev_err(&client->dev, "%s() error in configuring"
- "otg..\n", __func__);
+ charger->is_otg_enabled = 1;
+ return 0;
+error:
+ dev_err(&client->dev, "%s() error in enabling"
+ "otg..\n", __func__);
+ return ret;
+}
- /* ENABLE OTG */
- ret = smb349_configure_otg(client, 1);
- if (ret < 0)
- dev_err(&client->dev, "%s() error in configuring"
- "otg..\n", __func__);
+static int smb349_disable_otg(struct regulator_dev *otg_rdev)
+{
+ struct i2c_client *client = charger->client;
+ int ret;
- } else if ((from == OTG_STATE_A_HOST) && (to == OTG_STATE_A_SUSPEND)) {
+ /* Disable OTG */
+ ret = smb349_configure_otg(client, 0);
+ if (ret < 0)
+ goto error;
+ /* configure charger */
+ ret = smb349_configure_charger(client, 1);
+ if (ret < 0)
+ goto error;
- /* Disable OTG */
- ret = smb349_configure_otg(client, 0);
- if (ret < 0)
- dev_err(&client->dev, "%s() error in configuring"
- "otg..\n", __func__);
+ charger->is_otg_enabled = 0;
+ return 0;
+error:
+ dev_err(&client->dev, "%s() error in disabling"
+ "otg..\n", __func__);
+ return ret;
+}
- /* configure charger */
- ret = smb349_configure_charger(client, 1);
- if (ret < 0)
- dev_err(&client->dev, "%s() error in configuring"
- "otg..\n", __func__);
- }
+static int smb349_is_otg_enabled(struct regulator_dev *otg_rdev)
+{
+ return charger->is_otg_enabled;
}
static int smb349_enable_charging(struct regulator_dev *rdev,
@@ -381,15 +407,11 @@ static int smb349_enable_charging(struct regulator_dev *rdev,
if (!max_uA) {
charger->state = stopped;
- /* Disable charger */
- ret = smb349_configure_charger(client, 0);
- if (ret < 0) {
- dev_err(&client->dev, "%s() error in configuring"
- "charger..\n", __func__);
- return ret;
- }
charger->chrg_type = NONE;
} else {
+ /* Wait for SMB349 to reload OTP setting and detect type*/
+ msleep(500);
+
ret = smb349_read(client, SMB349_STS_REG_D);
if (ret < 0) {
dev_err(&client->dev, "%s(): Failed in reading register"
@@ -414,13 +436,103 @@ static int smb349_enable_charging(struct regulator_dev *rdev,
if (charger->charger_cb)
charger->charger_cb(charger->state, charger->chrg_type,
charger->charger_cb_data);
-return 0;
+ return 0;
}
static struct regulator_ops smb349_tegra_regulator_ops = {
.set_current_limit = smb349_enable_charging,
};
+static struct regulator_ops smb349_tegra_otg_regulator_ops = {
+ .enable = smb349_enable_otg,
+ .disable = smb349_disable_otg,
+ .is_enabled = smb349_is_otg_enabled,
+};
+
+#if defined(CONFIG_DEBUG_FS)
+static struct dentry *smb349_dentry_regs;
+
+static int smb349_dump_regs(struct i2c_client *client, u8 *addrs, int num_addrs,
+ char *buf, ssize_t *len)
+{
+ ssize_t count = *len;
+ int ret = 0;
+ int i;
+
+ if (count >= PAGE_SIZE - 1)
+ return -ERANGE;
+
+ for (i = 0; i < num_addrs; i++) {
+ count += sprintf(buf + count, "0x%02x: ", addrs[i]);
+ if (count >= PAGE_SIZE - 1)
+ return -ERANGE;
+
+ ret = smb349_read(client, addrs[i]);
+ if (ret < 0)
+ count += sprintf(buf + count, "<read fail: %d\n", ret);
+ else
+ count += sprintf(buf + count, "0x%02x\n", ret);
+
+ if (count >= PAGE_SIZE - 1)
+ return -ERANGE;
+ }
+ *len = count;
+
+ return 0;
+}
+
+static ssize_t smb349_debugfs_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static u8 regs[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x09, 0x0A, 0x0B,
+ 0x0C, 0x0D, 0x0E, 0x10, 0x11, 0x12, 0x30, 0x31, 0x33, 0x35, 0x36,
+ 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F
+};
+static ssize_t smb349_debugfs_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ ssize_t ret;
+ struct i2c_client *client = file->private_data;
+ char *buf;
+ size_t len = 0;
+
+ buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ len += sprintf(buf + len, "SMB349 Registers\n");
+ smb349_dump_regs(client, regs, ARRAY_SIZE(regs), buf, &len);
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+ kfree(buf);
+ return ret;
+}
+
+static const struct file_operations smb349_debugfs_fops = {
+ .open = smb349_debugfs_open,
+ .read = smb349_debugfs_read,
+};
+
+static void smb349_debugfs_init(struct i2c_client *client)
+{
+ smb349_dentry_regs = debugfs_create_file(client->name,
+ 0444, 0, client,
+ &smb349_debugfs_fops);
+}
+
+static void smb349_debugfs_exit(struct i2c_client *client)
+{
+ debugfs_remove(smb349_dentry_regs);
+}
+#else
+static void smb349_debugfs_init(struct i2c_client *client){}
+static void smb349_debugfs_exit(struct i2c_client *client){}
+#endif /* CONFIG_DEBUG_FS */
+
static int __devinit smb349_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -438,6 +550,11 @@ static int __devinit smb349_probe(struct i2c_client *client,
charger->client = client;
charger->dev = &client->dev;
pdata = client->dev.platform_data;
+ if(!pdata) {
+ ret = -ENXIO;
+ goto error;
+ }
+
i2c_set_clientdata(client, charger);
/* Check battery presence */
@@ -448,11 +565,12 @@ static int __devinit smb349_probe(struct i2c_client *client,
goto regulator_error;
}
+ charger->is_otg_enabled = 0;
+
charger->reg_desc.name = "vbus_charger";
charger->reg_desc.ops = &smb349_tegra_regulator_ops;
charger->reg_desc.type = REGULATOR_CURRENT;
charger->reg_desc.id = pdata->regulator_id;
- charger->reg_desc.type = REGULATOR_CURRENT;
charger->reg_desc.owner = THIS_MODULE;
charger->reg_init_data.supply_regulator = NULL;
@@ -478,6 +596,9 @@ static int __devinit smb349_probe(struct i2c_client *client,
charger->rdev = regulator_register(&charger->reg_desc, charger->dev,
&charger->reg_init_data, charger);
+
+ smb349_debugfs_init(client);
+
if (IS_ERR(charger->rdev)) {
dev_err(&client->dev, "failed to register %s\n",
charger->reg_desc.name);
@@ -485,6 +606,42 @@ static int __devinit smb349_probe(struct i2c_client *client,
goto regulator_error;
}
+ charger->otg_reg_desc.name = "vbus_otg";
+ charger->otg_reg_desc.ops = &smb349_tegra_otg_regulator_ops;
+ charger->otg_reg_desc.type = REGULATOR_CURRENT;
+ charger->otg_reg_desc.id = pdata->otg_regulator_id;
+ charger->otg_reg_desc.type = REGULATOR_CURRENT;
+ charger->otg_reg_desc.owner = THIS_MODULE;
+
+ charger->otg_reg_init_data.supply_regulator = NULL;
+ charger->otg_reg_init_data.num_consumer_supplies =
+ pdata->num_otg_consumer_supplies;
+ charger->otg_reg_init_data.regulator_init = NULL;
+ charger->otg_reg_init_data.consumer_supplies =
+ pdata->otg_consumer_supplies;
+ charger->otg_reg_init_data.driver_data = charger;
+ charger->otg_reg_init_data.constraints.name = "vbus_otg";
+ charger->otg_reg_init_data.constraints.min_uA = 0;
+ charger->otg_reg_init_data.constraints.max_uA = 500000;
+
+ charger->otg_reg_init_data.constraints.valid_modes_mask =
+ REGULATOR_MODE_NORMAL |
+ REGULATOR_MODE_STANDBY;
+
+ charger->otg_reg_init_data.constraints.valid_ops_mask =
+ REGULATOR_CHANGE_MODE |
+ REGULATOR_CHANGE_STATUS |
+ REGULATOR_CHANGE_CURRENT;
+
+ charger->otg_rdev = regulator_register(&charger->otg_reg_desc, charger->dev,
+ &charger->otg_reg_init_data, charger);
+ if (IS_ERR(charger->otg_rdev)) {
+ dev_err(&client->dev, "failed to register %s\n",
+ charger->otg_reg_desc.name);
+ ret = PTR_ERR(charger->otg_rdev);
+ goto otg_regulator_error;
+ }
+
/* disable OTG */
ret = smb349_configure_otg(client, 0);
if (ret < 0) {
@@ -516,12 +673,11 @@ static int __devinit smb349_probe(struct i2c_client *client,
}
}
- ret = register_otg_callback(smb349_otg_status, charger);
- if (ret < 0)
- goto error;
-
return 0;
error:
+ smb349_debugfs_exit(client);
+ regulator_unregister(charger->otg_rdev);
+otg_regulator_error:
regulator_unregister(charger->rdev);
regulator_error:
kfree(charger);
@@ -533,7 +689,9 @@ static int __devexit smb349_remove(struct i2c_client *client)
{
struct smb349_charger *charger = i2c_get_clientdata(client);
+ smb349_debugfs_exit(client);
regulator_unregister(charger->rdev);
+ regulator_unregister(charger->otg_rdev);
kfree(charger);
return 0;
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index d3cb8e6ff099..28c58a1c19b1 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -117,6 +117,15 @@ config REGULATOR_MAX8952
via I2C bus. Maxim 8952 has one voltage output and supports 4 DVS
modes ranging from 0.77V to 1.40V by 0.01V steps.
+config REGULATOR_MAX8973
+ tristate "Maxim MAX8973 Power Regulator"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ This driver supports MAX8973 voltage regulator chip.
+ The MAX8973 high-efficiency, three-phase, DC-DC step-down switching
+ regulator delivers up to 9A of output current.
+
config REGULATOR_MAX8997
tristate "Maxim 8997/8966 regulator"
depends on MFD_MAX8997
@@ -248,6 +257,16 @@ config REGULATOR_AB3100
AB3100 analog baseband dealing with power regulators
for the system.
+config REGULATOR_RC5T583
+ tristate "RICOH RC5T583 Power regulators"
+ depends on MFD_RC5T583
+ help
+ Select this option to enable the power regulator of RICOH
+ PMIC RC5T583.
+ This driver supports the control of different power rails of device
+ through regulator interface. The device supports multiple DCDC/LDO
+ outputs which can be controlled by i2c communication.
+
config REGULATOR_TPS6105X
tristate "TI TPS6105X Power regulators"
depends on TPS6105X
@@ -345,6 +364,16 @@ config REGULATOR_TPS62360
high-frequency synchronous step down dc-dc converter optimized
for battery-powered portable applications.
+config REGULATOR_TPS6238X0
+ tristate "TI TPS623850/TPS623860/TPS623870 Power Regulator"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ This driver supports TPS6238X0 voltage regulator chip. This
+ regulator is meant for processor core supply. This chip is
+ high-frequency synchronous step down dc-dc converter optimized
+ for battery-powered portable applications.
+
config REGULATOR_AAT2870
tristate "AnalogicTech AAT2870 Regulators"
depends on MFD_AAT2870_CORE
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 4fc5c3f275ab..a25ff34afcbc 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o
obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o
obj-$(CONFIG_REGULATOR_MAX8925) += max8925-regulator.o
obj-$(CONFIG_REGULATOR_MAX8952) += max8952.o
+obj-$(CONFIG_REGULATOR_MAX8973) += max8973-regulator.o
obj-$(CONFIG_REGULATOR_MAX8997) += max8997.o
obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o
obj-$(CONFIG_REGULATOR_MAX8907C) += max8907c-regulator.o
@@ -39,6 +40,7 @@ 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_AB3100) += ab3100.o
+obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-regulator.o
obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o
obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o
@@ -52,6 +54,7 @@ obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o
obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o
obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o
obj-$(CONFIG_REGULATOR_TPS62360) += tps62360-regulator.o
+obj-$(CONFIG_REGULATOR_TPS6238X0) += tps6238x0-regulator.o
obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o
obj-$(CONFIG_REGULATOR_FAN53555) += fan53555-regulator.o
ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
diff --git a/drivers/regulator/max77663-regulator.c b/drivers/regulator/max77663-regulator.c
index c9001c0a3e9f..55d2526b4490 100644
--- a/drivers/regulator/max77663-regulator.c
+++ b/drivers/regulator/max77663-regulator.c
@@ -280,7 +280,7 @@ static int max77663_regulator_set_fps(struct max77663_regulator *reg)
fps_mask |= FPS_PD_PERIOD_MASK;
}
- if (fps_val)
+ if (fps_val || fps_mask)
ret = max77663_regulator_cache_write(reg,
reg->regs[FPS_REG].addr, fps_mask,
fps_val, &reg->regs[FPS_REG].val);
diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c
new file mode 100644
index 000000000000..8d87970a1b31
--- /dev/null
+++ b/drivers/regulator/max8973-regulator.c
@@ -0,0 +1,606 @@
+/*
+ * max8973-regulator.c -- Maxim max8973
+ *
+ * Regulator driver for MAXIM 8973 DC-DC step-down switching regulator.
+ *
+ * Copyright (c) 2012, NVIDIA Corporation.
+ *
+ * Author: Laxman Dewangan <ldewangan@nvidia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * 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.
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/max8973-regulator.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+
+/* Register definitions */
+#define MAX8973_VOUT 0x0
+#define MAX8973_VOUT_DVS 0x1
+#define MAX8973_CONTROL1 0x2
+#define MAX8973_CONTROL2 0x3
+#define MAX8973_CHIPID1 0x4
+#define MAX8973_CHIPID2 0x5
+
+#define MAX8973_MAX_VOUT_REG 2
+
+/* MAX8973_VOUT */
+#define MAX8973_VOUT_ENABLE BIT(7)
+#define MAX8973_VOUT_MASK 0x7F
+
+/* MAX8973_VOUT_DVS */
+#define MAX8973_DVS_VOUT_MASK 0x7F
+
+/* MAX8973_CONTROL1 */
+#define MAX8973_SNS_ENABLE BIT(7)
+#define MAX8973_FPWM_EN_M BIT(6)
+#define MAX8973_NFSR_ENABLE BIT(5)
+#define MAX8973_AD_ENABLE BIT(4)
+#define MAX8973_BIAS_ENABLE BIT(3)
+#define MAX8973_FREQSHIFT_9PER BIT(2)
+
+#define MAX8973_RAMP_12mV_PER_US 0x0
+#define MAX8973_RAMP_25mV_PER_US 0x1
+#define MAX8973_RAMP_50mV_PER_US 0x2
+#define MAX8973_RAMP_200mV_PER_US 0x3
+
+/* MAX8973_CONTROL2 */
+#define MAX8973_WDTMR_ENABLE BIT(6)
+#define MAX8973_DISCH_ENBABLE BIT(5)
+#define MAX8973_FT_ENABLE BIT(4)
+
+#define MAX8973_CKKADV_TRIP_DISABLE 0xC
+#define MAX8973_CKKADV_TRIP_75mV_PER_US 0x0
+#define MAX8973_CKKADV_TRIP_150mV_PER_US 0x4
+#define MAX8973_CKKADV_TRIP_75mV_PER_US_HIST_DIS 0x8
+
+#define MAX8973_INDUCTOR_MIN_30_PER 0x0
+#define MAX8973_INDUCTOR_NOMINAL 0x1
+#define MAX8973_INDUCTOR_PLUS_30_PER 0x2
+#define MAX8973_INDUCTOR_PLUS_60_PER 0x3
+
+#define MAX8973_MIN_VOLATGE 606250
+#define MAX8973_MAX_VOLATGE 1400000
+#define MAX8973_VOLATGE_STEP 6250
+#define MAX8973_BUCK_N_VOLTAGE \
+ (((MAX8973_MAX_VOLATGE - MAX8973_MIN_VOLATGE) / MAX8973_VOLATGE_STEP) \
+ + 1)
+
+/* Maxim 8973 chip information */
+struct max8973_chip {
+ struct device *dev;
+ struct regulator_desc desc;
+ struct regulator_dev *rdev;
+ struct regmap *regmap;
+ bool enable_external_control;
+ int dvs_gpio;
+ int lru_index[MAX8973_MAX_VOUT_REG];
+ int curr_vout_val[MAX8973_MAX_VOUT_REG];
+ int curr_vout_reg;
+ int curr_gpio_val;
+ int change_uv_per_us;
+ bool valid_dvs_gpio;
+};
+
+/*
+ * find_voltage_set_register: Find new voltage configuration register (VOUT).
+ * The finding of the new VOUT register will be based on the LRU mechanism.
+ * Each VOUT register will have different voltage configured . This
+ * Function will look if any of the VOUT register have requested voltage set
+ * or not.
+ * - If it is already there then it will make that register as most
+ * recently used and return as found so that caller need not to set
+ * the VOUT register but need to set the proper gpios to select this
+ * VOUT register.
+ * - If requested voltage is not found then it will use the least
+ * recently mechanism to get new VOUT register for new configuration
+ * and will return not_found so that caller need to set new VOUT
+ * register and then gpios (both).
+ */
+static bool find_voltage_set_register(struct max8973_chip *tps,
+ int req_vsel, int *vout_reg, int *gpio_val)
+{
+ int i;
+ bool found = false;
+ int new_vout_reg = tps->lru_index[MAX8973_MAX_VOUT_REG - 1];
+ int found_index = MAX8973_MAX_VOUT_REG - 1;
+
+ for (i = 0; i < MAX8973_MAX_VOUT_REG; ++i) {
+ if (tps->curr_vout_val[tps->lru_index[i]] == req_vsel) {
+ new_vout_reg = tps->lru_index[i];
+ found_index = i;
+ found = true;
+ goto update_lru_index;
+ }
+ }
+
+update_lru_index:
+ for (i = found_index; i > 0; i--)
+ tps->lru_index[i] = tps->lru_index[i - 1];
+
+ tps->lru_index[0] = new_vout_reg;
+ *gpio_val = new_vout_reg;
+ *vout_reg = MAX8973_VOUT + new_vout_reg;
+ return found;
+}
+
+static int max8973_dcdc_get_voltage_sel(struct regulator_dev *rdev)
+{
+ struct max8973_chip *max = rdev_get_drvdata(rdev);
+ unsigned int data;
+ int ret;
+
+ ret = regmap_read(max->regmap, max->curr_vout_reg, &data);
+ if (ret < 0) {
+ dev_err(max->dev, "%s(): register %d read failed with err %d\n",
+ __func__, max->curr_vout_reg, ret);
+ return ret;
+ }
+ return data & MAX8973_VOUT_MASK;
+}
+
+static int max8973_dcdc_set_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV, unsigned *selector)
+{
+ struct max8973_chip *max = rdev_get_drvdata(rdev);
+ int vsel;
+ int ret;
+ bool found = false;
+ int vout_reg = max->curr_vout_reg;
+ int gpio_val = max->curr_gpio_val;
+
+ if ((max_uV < min_uV) || (max_uV < MAX8973_MIN_VOLATGE) ||
+ (min_uV > MAX8973_MAX_VOLATGE))
+ return -EINVAL;
+
+ vsel = DIV_ROUND_UP(min_uV - MAX8973_MIN_VOLATGE, MAX8973_VOLATGE_STEP);
+ if (selector)
+ *selector = (vsel & MAX8973_VOUT_MASK);
+
+ /*
+ * If gpios are available to select the VOUT register then least
+ * recently used register for new configuration.
+ */
+ if (max->valid_dvs_gpio)
+ found = find_voltage_set_register(max, vsel,
+ &vout_reg, &gpio_val);
+
+ if (!found) {
+ ret = regmap_update_bits(max->regmap, vout_reg,
+ MAX8973_VOUT_MASK, vsel);
+ if (ret < 0) {
+ dev_err(max->dev,
+ "%s(): register %d update failed with err %d\n",
+ __func__, vout_reg, ret);
+ return ret;
+ }
+ max->curr_vout_reg = vout_reg;
+ max->curr_vout_val[gpio_val] = vsel;
+ }
+
+ /* Select proper VOUT register vio gpios */
+ if (max->valid_dvs_gpio) {
+ gpio_set_value_cansleep(max->dvs_gpio, gpio_val & 0x1);
+ max->curr_gpio_val = gpio_val;
+ }
+ return 0;
+}
+
+static int max8973_dcdc_list_voltage(struct regulator_dev *rdev,
+ unsigned selector)
+{
+ if (selector >= MAX8973_BUCK_N_VOLTAGE)
+ return -EINVAL;
+
+ return MAX8973_MIN_VOLATGE + selector * MAX8973_VOLATGE_STEP;
+}
+
+static int max8973_dcdc_set_voltage_time_sel(struct regulator_dev *rdev,
+ unsigned int old_selector, unsigned int new_selector)
+{
+ struct max8973_chip *max = rdev_get_drvdata(rdev);
+ int old_uV, new_uV;
+
+ old_uV = max8973_dcdc_list_voltage(rdev, old_selector);
+ if (old_uV < 0)
+ return old_uV;
+
+ new_uV = max8973_dcdc_list_voltage(rdev, new_selector);
+ if (new_uV < 0)
+ return new_uV;
+
+ return DIV_ROUND_UP(abs(old_uV - new_uV), max->change_uv_per_us);
+}
+static int max8973_dcdc_enable(struct regulator_dev *rdev)
+{
+ struct max8973_chip *max = rdev_get_drvdata(rdev);
+ int ret;
+
+ if (max->enable_external_control)
+ return 0;
+
+ ret = regmap_update_bits(max->regmap, MAX8973_VOUT,
+ MAX8973_VOUT_ENABLE, MAX8973_VOUT_ENABLE);
+ if (ret < 0)
+ dev_err(max->dev, "%s(): register %d update failed with err %d",
+ __func__, MAX8973_VOUT, ret);
+ return ret;
+}
+
+static int max8973_dcdc_disable(struct regulator_dev *rdev)
+{
+ struct max8973_chip *max = rdev_get_drvdata(rdev);
+ int ret = 0;
+
+ if (max->enable_external_control)
+ return 0;
+
+ ret = regmap_update_bits(max->regmap, MAX8973_VOUT,
+ MAX8973_VOUT_ENABLE, 0);
+ if (ret < 0)
+ dev_err(max->dev, "%s(): register %d update failed with err %d",
+ __func__, MAX8973_VOUT, ret);
+ return ret;
+}
+
+static int max8973_dcdc_is_enabled(struct regulator_dev *rdev)
+{
+ struct max8973_chip *max = rdev_get_drvdata(rdev);
+ int ret;
+ unsigned int data;
+
+ if (max->enable_external_control)
+ return 1;
+
+ ret = regmap_read(max->regmap, MAX8973_VOUT, &data);
+ if (ret < 0) {
+ dev_err(max->dev, "%s(): register %d read failed with err %d",
+ __func__, max->curr_vout_reg, ret);
+ return ret;
+ }
+
+ return !!(data & MAX8973_VOUT_ENABLE);
+}
+
+static int max8973_dcdc_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+ struct max8973_chip *max = rdev_get_drvdata(rdev);
+ int ret;
+ int pwm;
+
+ /* Enable force PWM mode in FAST mode only. */
+ switch (mode) {
+ case REGULATOR_MODE_FAST:
+ pwm = MAX8973_FPWM_EN_M;
+ break;
+
+ case REGULATOR_MODE_NORMAL:
+ pwm = 0;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ ret = regmap_update_bits(max->regmap, MAX8973_CONTROL1,
+ MAX8973_FPWM_EN_M, pwm);
+ if (ret < 0)
+ dev_err(max->dev,
+ "%s(): register %d update failed with err %d\n",
+ __func__, MAX8973_CONTROL1, ret);
+ return ret;
+}
+
+static unsigned int max8973_dcdc_get_mode(struct regulator_dev *rdev)
+{
+ struct max8973_chip *max = rdev_get_drvdata(rdev);
+ unsigned int data;
+ int ret;
+
+ ret = regmap_read(max->regmap, MAX8973_CONTROL1, &data);
+ if (ret < 0) {
+ dev_err(max->dev, "%s(): register %d read failed with err %d\n",
+ __func__, MAX8973_CONTROL1, ret);
+ return ret;
+ }
+ return (data & MAX8973_FPWM_EN_M) ?
+ REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL;
+}
+
+static struct regulator_ops max8973_dcdc_ops = {
+ .get_voltage_sel = max8973_dcdc_get_voltage_sel,
+ .set_voltage = max8973_dcdc_set_voltage,
+ .list_voltage = max8973_dcdc_list_voltage,
+ .set_voltage_time_sel = max8973_dcdc_set_voltage_time_sel,
+ .enable = max8973_dcdc_enable,
+ .disable = max8973_dcdc_disable,
+ .is_enabled = max8973_dcdc_is_enabled,
+ .set_mode = max8973_dcdc_set_mode,
+ .get_mode = max8973_dcdc_get_mode,
+};
+
+static int __devinit max8973_init_dcdc(struct max8973_chip *max,
+ struct max8973_regulator_platform_data *pdata)
+{
+ int ret;
+ uint8_t control1 = 0;
+ uint8_t control2 = 0;
+
+ if (pdata->control_flags & MAX8973_CONTROL_REMOTE_SENSE_ENABLE)
+ control1 |= MAX8973_SNS_ENABLE;
+
+ if (!(pdata->control_flags & MAX8973_CONTROL_FALLING_SLEW_RATE_ENABLE))
+ control1 |= MAX8973_NFSR_ENABLE;
+
+ if (pdata->control_flags & MAX8973_CONTROL_OUTPUT_ACTIVE_DISCH_ENABLE)
+ control1 |= MAX8973_AD_ENABLE;
+
+ if (pdata->control_flags & MAX8973_CONTROL_BIAS_ENABLE)
+ control1 |= MAX8973_BIAS_ENABLE;
+
+ if (pdata->control_flags & MAX8973_CONTROL_FREQ_SHIFT_9PER_ENABLE)
+ control1 |= MAX8973_FREQSHIFT_9PER;
+
+ switch (pdata->control_flags & MAX8973_CONTROL_SLEW_RATE_200MV_PER_US) {
+ case MAX8973_CONTROL_SLEW_RATE_12_5mV_PER_US:
+ control1 = MAX8973_RAMP_12mV_PER_US;
+ max->change_uv_per_us = 12500;
+ break;
+
+ case MAX8973_CONTROL_SLEW_RATE_25mV_PER_US:
+ control1 = MAX8973_RAMP_25mV_PER_US;
+ max->change_uv_per_us = 25000;
+ break;
+
+ case MAX8973_CONTROL_SLEW_RATE_50mV_PER_US:
+ control1 = MAX8973_RAMP_50mV_PER_US;
+ max->change_uv_per_us = 50000;
+ break;
+
+ case MAX8973_CONTROL_SLEW_RATE_200MV_PER_US:
+ control1 = MAX8973_RAMP_200mV_PER_US;
+ max->change_uv_per_us = 200000;
+ break;
+ }
+
+ if (!(pdata->control_flags & MAX8973_CONTROL_PULL_DOWN_ENABLE))
+ control2 |= MAX8973_DISCH_ENBABLE;
+
+ switch (pdata->control_flags &
+ MAX8973_CONTROL_CLKADV_TRIP_75mV_PER_US) {
+ case MAX8973_CONTROL_CLKADV_TRIP_DISABLED:
+ control2 |= MAX8973_CKKADV_TRIP_DISABLE;
+ break;
+
+ case MAX8973_CONTROL_CLKADV_TRIP_75mV_PER_US:
+ control2 |= MAX8973_CKKADV_TRIP_75mV_PER_US;
+ break;
+
+ case MAX8973_CONTROL_CLKADV_TRIP_150mV_PER_US:
+ control2 |= MAX8973_CKKADV_TRIP_150mV_PER_US;
+ break;
+
+ case MAX8973_CONTROL_CLKADV_TRIP_75mV_PER_US_HIST_DIS:
+ control2 |= MAX8973_CKKADV_TRIP_75mV_PER_US_HIST_DIS;
+ break;
+ }
+
+ switch (pdata->control_flags &
+ MAX8973_CONTROL_INDUCTOR_VALUE_PLUS_60_PER) {
+ case MAX8973_CONTROL_INDUCTOR_VALUE_NOMINAL:
+ control2 |= MAX8973_INDUCTOR_NOMINAL;
+ break;
+
+ case MAX8973_CONTROL_INDUCTOR_VALUE_MINUS_30_PER:
+ control2 |= MAX8973_INDUCTOR_MIN_30_PER;
+ break;
+
+ case MAX8973_CONTROL_INDUCTOR_VALUE_PLUS_30_PER:
+ control2 |= MAX8973_INDUCTOR_PLUS_30_PER;
+ break;
+
+ case MAX8973_CONTROL_INDUCTOR_VALUE_PLUS_60_PER:
+ control2 |= MAX8973_INDUCTOR_PLUS_60_PER;
+ break;
+ }
+
+ ret = regmap_write(max->regmap, MAX8973_CONTROL1, control1);
+ if (ret < 0) {
+ dev_err(max->dev, "%s(): register %d write failed with err %d",
+ __func__, MAX8973_CONTROL1, ret);
+ return ret;
+ }
+
+ ret = regmap_write(max->regmap, MAX8973_CONTROL2, control2);
+ if (ret < 0) {
+ dev_err(max->dev, "%s(): register %d write failed with err %d",
+ __func__, MAX8973_CONTROL2, ret);
+ return ret;
+ }
+
+ /* If external control is enabled then disable EN bit */
+ if (max->enable_external_control) {
+ ret = regmap_update_bits(max->regmap, MAX8973_VOUT,
+ MAX8973_VOUT_ENABLE, 0);
+ if (ret < 0)
+ dev_err(max->dev, "%s(): register %d update failed with err %d",
+ __func__, MAX8973_VOUT, ret);
+ }
+ return ret;
+}
+
+static const struct regmap_config max8973_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = MAX8973_CHIPID2,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static int __devinit max8973_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct max8973_regulator_platform_data *pdata;
+ struct regulator_dev *rdev;
+ struct max8973_chip *max;
+ int ret;
+
+ pdata = client->dev.platform_data;
+ if (!pdata) {
+ dev_err(&client->dev, "%s(): No Platform data", __func__);
+ return -EIO;
+ }
+
+ max = devm_kzalloc(&client->dev, sizeof(*max), GFP_KERNEL);
+ if (!max) {
+ dev_err(&client->dev, "%s(): Memory allocation failed\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ max->dev = &client->dev;
+
+ max->desc.name = id->name;
+ max->desc.id = 0;
+ max->desc.ops = &max8973_dcdc_ops;
+ max->desc.type = REGULATOR_VOLTAGE;
+ max->desc.owner = THIS_MODULE;
+ max->regmap = devm_regmap_init_i2c(client, &max8973_regmap_config);
+ if (IS_ERR(max->regmap)) {
+ ret = PTR_ERR(max->regmap);
+ dev_err(&client->dev,
+ "%s(): regmap allocation failed with err %d\n",
+ __func__, ret);
+ return ret;
+ }
+ i2c_set_clientdata(client, max);
+
+ max->enable_external_control = pdata->enable_ext_control;
+ max->dvs_gpio = pdata->dvs_gpio;
+ max->curr_gpio_val = pdata->dvs_def_state;
+ max->curr_vout_reg = MAX8973_VOUT + pdata->dvs_def_state;
+ max->lru_index[0] = max->curr_vout_reg;
+ max->valid_dvs_gpio = false;
+
+ if (gpio_is_valid(max->dvs_gpio)) {
+ int gpio_flags;
+ int i;
+
+ gpio_flags = (pdata->dvs_def_state) ?
+ GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
+ ret = gpio_request_one(max->dvs_gpio,
+ gpio_flags, "max8973-dvs");
+ if (ret) {
+ dev_err(&client->dev,
+ "%s(): Could not obtain dvs GPIO %d: %d\n",
+ __func__, max->dvs_gpio, ret);
+ return ret;
+ }
+ max->valid_dvs_gpio = true;
+
+ /*
+ * Initialize the lru index with vout_reg id
+ * The index 0 will be most recently used and
+ * set with the max->curr_vout_reg */
+ for (i = 0; i < MAX8973_MAX_VOUT_REG; ++i)
+ max->lru_index[i] = i;
+ max->lru_index[0] = max->curr_vout_reg;
+ max->lru_index[max->curr_vout_reg] = 0;
+ }
+
+ ret = max8973_init_dcdc(max, pdata);
+ if (ret < 0) {
+ dev_err(max->dev, "%s(): Init failed with err = %d\n",
+ __func__, ret);
+ goto err_init;
+ }
+
+ /* Register the regulators */
+ rdev = regulator_register(&max->desc, &client->dev,
+ pdata->reg_init_data, max);
+ if (IS_ERR(rdev)) {
+ dev_err(max->dev,
+ "%s(): regulator register failed with err %s\n",
+ __func__, id->name);
+ ret = PTR_ERR(rdev);
+ goto err_init;
+ }
+
+ max->rdev = rdev;
+ return 0;
+
+err_init:
+ if (gpio_is_valid(max->dvs_gpio))
+ gpio_free(max->dvs_gpio);
+ return ret;
+}
+
+/**
+ * max8973_remove - max8973 driver i2c remove handler
+ * @client: i2c driver client device structure
+ *
+ * Unregister TPS driver as an i2c client device driver
+ */
+static int __devexit max8973_remove(struct i2c_client *client)
+{
+ struct max8973_chip *max = i2c_get_clientdata(client);
+
+ if (gpio_is_valid(max->dvs_gpio))
+ gpio_free(max->dvs_gpio);
+
+ regulator_unregister(max->rdev);
+ return 0;
+}
+
+static const struct i2c_device_id max8973_id[] = {
+ {.name = "max8973",},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, max8973_id);
+
+static struct i2c_driver max8973_i2c_driver = {
+ .driver = {
+ .name = "max8973",
+ .owner = THIS_MODULE,
+ },
+ .probe = max8973_probe,
+ .remove = __devexit_p(max8973_remove),
+ .id_table = max8973_id,
+};
+
+static int __init max8973_init(void)
+{
+ return i2c_add_driver(&max8973_i2c_driver);
+}
+subsys_initcall(max8973_init);
+
+static void __exit max8973_cleanup(void)
+{
+ i2c_del_driver(&max8973_i2c_driver);
+}
+module_exit(max8973_cleanup);
+
+MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
+MODULE_DESCRIPTION("MAX8973 voltage regulator driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/rc5t583-regulator.c b/drivers/regulator/rc5t583-regulator.c
new file mode 100644
index 000000000000..81a03b281fa0
--- /dev/null
+++ b/drivers/regulator/rc5t583-regulator.c
@@ -0,0 +1,363 @@
+/*
+ * Regulator driver for RICOH RC5T583 power management chip.
+ *
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved.
+ * Author: Laxman dewangan <ldewangan@nvidia.com>
+ *
+ * based on code
+ * Copyright (C) 2011 RICOH COMPANY,LTD
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/gpio.h>
+#include <linux/mfd/rc5t583.h>
+
+struct rc5t583_regulator_info {
+ int deepsleep_id;
+
+ /* Regulator register address.*/
+ uint8_t reg_en_reg;
+ uint8_t en_bit;
+ uint8_t reg_disc_reg;
+ uint8_t disc_bit;
+ uint8_t vout_reg;
+ uint8_t vout_mask;
+ uint8_t deepsleep_reg;
+
+ /* Chip constraints on regulator behavior */
+ int min_uV;
+ int max_uV;
+ int step_uV;
+
+ /* Regulator specific turn-on delay and voltage settling time*/
+ int enable_uv_per_us;
+ int change_uv_per_us;
+
+ /* Used by regulator core */
+ struct regulator_desc desc;
+};
+
+struct rc5t583_regulator {
+ struct rc5t583_regulator_info *reg_info;
+
+ /* Devices */
+ struct device *dev;
+ struct rc5t583 *mfd;
+ struct regulator_dev *rdev;
+};
+
+static int rc5t583_reg_is_enabled(struct regulator_dev *rdev)
+{
+ struct rc5t583_regulator *reg = rdev_get_drvdata(rdev);
+ struct rc5t583_regulator_info *ri = reg->reg_info;
+ uint8_t control;
+ int ret;
+
+ ret = rc5t583_read(reg->mfd->dev, ri->reg_en_reg, &control);
+ if (ret < 0) {
+ dev_err(&rdev->dev,
+ "Error in reading the control register 0x%02x\n",
+ ri->reg_en_reg);
+ return ret;
+ }
+ return !!(control & BIT(ri->en_bit));
+}
+
+static int rc5t583_reg_enable(struct regulator_dev *rdev)
+{
+ struct rc5t583_regulator *reg = rdev_get_drvdata(rdev);
+ struct rc5t583_regulator_info *ri = reg->reg_info;
+ int ret;
+
+ ret = rc5t583_set_bits(reg->mfd->dev, ri->reg_en_reg,
+ (1 << ri->en_bit));
+ if (ret < 0) {
+ dev_err(&rdev->dev,
+ "Error in setting bit of STATE register 0x%02x\n",
+ ri->reg_en_reg);
+ return ret;
+ }
+ return ret;
+}
+
+static int rc5t583_reg_disable(struct regulator_dev *rdev)
+{
+ struct rc5t583_regulator *reg = rdev_get_drvdata(rdev);
+ struct rc5t583_regulator_info *ri = reg->reg_info;
+ int ret;
+
+ ret = rc5t583_clear_bits(reg->mfd->dev, ri->reg_en_reg,
+ (1 << ri->en_bit));
+ if (ret < 0)
+ dev_err(&rdev->dev,
+ "Error in clearing bit of STATE register 0x%02x\n",
+ ri->reg_en_reg);
+
+ return ret;
+}
+
+static int rc5t583_list_voltage(struct regulator_dev *rdev, unsigned selector)
+{
+ struct rc5t583_regulator *reg = rdev_get_drvdata(rdev);
+ struct rc5t583_regulator_info *ri = reg->reg_info;
+ return ri->min_uV + (ri->step_uV * selector);
+}
+
+static int rc5t583_set_voltage_sel(struct regulator_dev *rdev,
+ unsigned int selector)
+{
+ struct rc5t583_regulator *reg = rdev_get_drvdata(rdev);
+ struct rc5t583_regulator_info *ri = reg->reg_info;
+ int ret;
+ if (selector >= rdev->desc->n_voltages) {
+ dev_err(&rdev->dev, "Invalid selector 0x%02x\n", selector);
+ return -EINVAL;
+ }
+
+ ret = rc5t583_update(reg->mfd->dev, ri->vout_reg,
+ selector, ri->vout_mask);
+ if (ret < 0)
+ dev_err(&rdev->dev,
+ "Error in update voltage register 0x%02x\n", ri->vout_reg);
+ return ret;
+}
+
+static int rc5t583_get_voltage_sel(struct regulator_dev *rdev)
+{
+ struct rc5t583_regulator *reg = rdev_get_drvdata(rdev);
+ struct rc5t583_regulator_info *ri = reg->reg_info;
+ uint8_t vsel;
+ int ret;
+ ret = rc5t583_read(reg->mfd->dev, ri->vout_reg, &vsel);
+ if (ret < 0) {
+ dev_err(&rdev->dev,
+ "Error in reading voltage register 0x%02x\n", ri->vout_reg);
+ return ret;
+ }
+ return vsel & ri->vout_mask;
+}
+
+static int rc5t583_regulator_enable_time(struct regulator_dev *rdev)
+{
+ struct rc5t583_regulator *reg = rdev_get_drvdata(rdev);
+ int vsel = rc5t583_get_voltage_sel(rdev);
+ int curr_uV = rc5t583_list_voltage(rdev, vsel);
+ return DIV_ROUND_UP(curr_uV, reg->reg_info->enable_uv_per_us);
+}
+
+static int rc5t583_set_voltage_time_sel(struct regulator_dev *rdev,
+ unsigned int old_selector, unsigned int new_selector)
+{
+ struct rc5t583_regulator *reg = rdev_get_drvdata(rdev);
+ int old_uV, new_uV;
+ old_uV = rc5t583_list_voltage(rdev, old_selector);
+
+ if (old_uV < 0)
+ return old_uV;
+
+ new_uV = rc5t583_list_voltage(rdev, new_selector);
+ if (new_uV < 0)
+ return new_uV;
+
+ return DIV_ROUND_UP(abs(old_uV - new_uV),
+ reg->reg_info->change_uv_per_us);
+}
+
+
+static struct regulator_ops rc5t583_ops = {
+ .is_enabled = rc5t583_reg_is_enabled,
+ .enable = rc5t583_reg_enable,
+ .disable = rc5t583_reg_disable,
+ .enable_time = rc5t583_regulator_enable_time,
+ .get_voltage_sel = rc5t583_get_voltage_sel,
+ .set_voltage_sel = rc5t583_set_voltage_sel,
+ .list_voltage = rc5t583_list_voltage,
+ .set_voltage_time_sel = rc5t583_set_voltage_time_sel,
+};
+
+#define RC5T583_REG(_id, _en_reg, _en_bit, _disc_reg, _disc_bit, _vout_reg, \
+ _vout_mask, _ds_reg, _min_mv, _max_mv, _step_uV, _enable_mv) \
+{ \
+ .reg_en_reg = RC5T583_REG_##_en_reg, \
+ .en_bit = _en_bit, \
+ .reg_disc_reg = RC5T583_REG_##_disc_reg, \
+ .disc_bit = _disc_bit, \
+ .vout_reg = RC5T583_REG_##_vout_reg, \
+ .vout_mask = _vout_mask, \
+ .deepsleep_reg = RC5T583_REG_##_ds_reg, \
+ .min_uV = _min_mv * 1000, \
+ .max_uV = _max_mv * 1000, \
+ .step_uV = _step_uV, \
+ .enable_uv_per_us = _enable_mv * 1000, \
+ .change_uv_per_us = 40 * 1000, \
+ .deepsleep_id = RC5T583_DS_##_id, \
+ .desc = { \
+ .name = "rc5t583-regulator-"#_id, \
+ .id = RC5T583_REGULATOR_##_id, \
+ .n_voltages = (_max_mv - _min_mv) * 1000 / _step_uV + 1, \
+ .ops = &rc5t583_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ }, \
+}
+
+static struct rc5t583_regulator_info rc5t583_reg_info[RC5T583_REGULATOR_MAX] = {
+ RC5T583_REG(DC0, DC0CTL, 0, DC0CTL, 1, DC0DAC, 0x7F, DC0DAC_DS,
+ 700, 1500, 12500, 4),
+ RC5T583_REG(DC1, DC1CTL, 0, DC1CTL, 1, DC1DAC, 0x7F, DC1DAC_DS,
+ 700, 1500, 12500, 14),
+ RC5T583_REG(DC2, DC2CTL, 0, DC2CTL, 1, DC2DAC, 0x7F, DC2DAC_DS,
+ 900, 2400, 12500, 14),
+ RC5T583_REG(DC3, DC3CTL, 0, DC3CTL, 1, DC3DAC, 0x7F, DC3DAC_DS,
+ 900, 2400, 12500, 14),
+ RC5T583_REG(LDO0, LDOEN2, 0, LDODIS2, 0, LDO0DAC, 0x7F, LDO0DAC_DS,
+ 900, 3400, 25000, 160),
+ RC5T583_REG(LDO1, LDOEN2, 1, LDODIS2, 1, LDO1DAC, 0x7F, LDO1DAC_DS,
+ 900, 3400, 25000, 160),
+ RC5T583_REG(LDO2, LDOEN2, 2, LDODIS2, 2, LDO2DAC, 0x7F, LDO2DAC_DS,
+ 900, 3400, 25000, 160),
+ RC5T583_REG(LDO3, LDOEN2, 3, LDODIS2, 3, LDO3DAC, 0x7F, LDO3DAC_DS,
+ 900, 3400, 25000, 160),
+ RC5T583_REG(LDO4, LDOEN2, 4, LDODIS2, 4, LDO4DAC, 0x3F, LDO4DAC_DS,
+ 750, 1500, 12500, 133),
+ RC5T583_REG(LDO5, LDOEN2, 5, LDODIS2, 5, LDO5DAC, 0x7F, LDO5DAC_DS,
+ 900, 3400, 25000, 267),
+ RC5T583_REG(LDO6, LDOEN2, 6, LDODIS2, 6, LDO6DAC, 0x7F, LDO6DAC_DS,
+ 900, 3400, 25000, 133),
+ RC5T583_REG(LDO7, LDOEN2, 7, LDODIS2, 7, LDO7DAC, 0x7F, LDO7DAC_DS,
+ 900, 3400, 25000, 233),
+ RC5T583_REG(LDO8, LDOEN1, 0, LDODIS1, 0, LDO8DAC, 0x7F, LDO8DAC_DS,
+ 900, 3400, 25000, 233),
+ RC5T583_REG(LDO9, LDOEN1, 1, LDODIS1, 1, LDO9DAC, 0x7F, LDO9DAC_DS,
+ 900, 3400, 25000, 133),
+};
+
+static int __devinit rc5t583_regulator_probe(struct platform_device *pdev)
+{
+ struct rc5t583 *rc5t583 = dev_get_drvdata(pdev->dev.parent);
+ struct rc5t583_platform_data *pdata = dev_get_platdata(rc5t583->dev);
+ struct regulator_init_data *reg_data;
+ struct rc5t583_regulator *reg = NULL;
+ struct rc5t583_regulator *regs;
+ struct regulator_dev *rdev;
+ struct rc5t583_regulator_info *ri;
+ int ret;
+ int id;
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "No platform data, exiting...\n");
+ return -ENODEV;
+ }
+
+ regs = devm_kzalloc(&pdev->dev, RC5T583_REGULATOR_MAX *
+ sizeof(struct rc5t583_regulator), GFP_KERNEL);
+ if (!regs) {
+ dev_err(&pdev->dev, "Memory allocation failed exiting..\n");
+ return -ENOMEM;
+ }
+
+
+ for (id = 0; id < RC5T583_REGULATOR_MAX; ++id) {
+ reg_data = pdata->reg_init_data[id];
+
+ /* No need to register if there is no regulator data */
+ if (!reg_data)
+ continue;
+
+ reg = &regs[id];
+ ri = &rc5t583_reg_info[id];
+ reg->reg_info = ri;
+ reg->mfd = rc5t583;
+ reg->dev = &pdev->dev;
+
+ if (ri->deepsleep_id == RC5T583_DS_NONE)
+ goto skip_ext_pwr_config;
+
+ ret = rc5t583_ext_power_req_config(rc5t583->dev,
+ ri->deepsleep_id,
+ pdata->regulator_ext_pwr_control[id],
+ pdata->regulator_deepsleep_slot[id]);
+ /*
+ * Configuring external control is not a major issue,
+ * just give warning.
+ */
+ if (ret < 0)
+ dev_warn(&pdev->dev,
+ "Failed to configure ext control %d\n", id);
+
+skip_ext_pwr_config:
+ rdev = regulator_register(&ri->desc, &pdev->dev, reg_data, reg);
+ if (IS_ERR(rdev)) {
+ dev_err(&pdev->dev, "Failed to register regulator %s\n",
+ ri->desc.name);
+ ret = PTR_ERR(rdev);
+ goto clean_exit;
+ }
+ reg->rdev = rdev;
+ }
+ platform_set_drvdata(pdev, regs);
+ return 0;
+
+clean_exit:
+ while (--id >= 0)
+ regulator_unregister(regs[id].rdev);
+
+ return ret;
+}
+
+static int __devexit rc5t583_regulator_remove(struct platform_device *pdev)
+{
+ struct rc5t583_regulator *regs = platform_get_drvdata(pdev);
+ int id;
+
+ for (id = 0; id < RC5T583_REGULATOR_MAX; ++id)
+ regulator_unregister(regs[id].rdev);
+ return 0;
+}
+
+static struct platform_driver rc5t583_regulator_driver = {
+ .driver = {
+ .name = "rc5t583-regulator",
+ .owner = THIS_MODULE,
+ },
+ .probe = rc5t583_regulator_probe,
+ .remove = __devexit_p(rc5t583_regulator_remove),
+};
+
+static int __init rc5t583_regulator_init(void)
+{
+ return platform_driver_register(&rc5t583_regulator_driver);
+}
+subsys_initcall(rc5t583_regulator_init);
+
+static void __exit rc5t583_regulator_exit(void)
+{
+ platform_driver_unregister(&rc5t583_regulator_driver);
+}
+module_exit(rc5t583_regulator_exit);
+
+MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
+MODULE_DESCRIPTION("RC5T583 regulator driver");
+MODULE_ALIAS("platform:rc5t583-regulator");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/tps62360-regulator.c b/drivers/regulator/tps62360-regulator.c
index 7eaf08275376..7db148202436 100644
--- a/drivers/regulator/tps62360-regulator.c
+++ b/drivers/regulator/tps62360-regulator.c
@@ -1,7 +1,7 @@
/*
* tps62360.c -- TI tps62360
*
- * Driver for processor core supply tps62360 and tps62361B
+ * Driver for processor core supply tps62360, tps62361B, tps62362 and tps62363.
*
* Copyright (c) 2012, NVIDIA Corporation.
*
@@ -46,20 +46,20 @@
#define REG_RAMPCTRL 6
#define REG_CHIPID 8
-enum chips {TPS62360, TPS62361};
+#define FORCE_PWM_ENABLE BIT(7)
-#define TPS62360_BASE_VOLTAGE 770
+enum chips {TPS62360, TPS62361, TPS62362, TPS62363};
+
+#define TPS62360_BASE_VOLTAGE 770000
#define TPS62360_N_VOLTAGES 64
-#define TPS62361_BASE_VOLTAGE 500
+#define TPS62361_BASE_VOLTAGE 500000
#define TPS62361_N_VOLTAGES 128
/* tps 62360 chip information */
struct tps62360_chip {
- const char *name;
struct device *dev;
struct regulator_desc desc;
- struct i2c_client *client;
struct regulator_dev *rdev;
struct regmap *regmap;
int chip_id;
@@ -68,12 +68,12 @@ struct tps62360_chip {
int voltage_base;
u8 voltage_reg_mask;
bool en_internal_pulldn;
- bool en_force_pwm;
bool en_discharge;
bool valid_gpios;
int lru_index[4];
int curr_vset_vsel[4];
int curr_vset_id;
+ int change_uv_per_us;
};
/*
@@ -99,6 +99,7 @@ static bool find_voltage_set_register(struct tps62360_chip *tps,
bool found = false;
int new_vset_reg = tps->lru_index[3];
int found_index = 3;
+
for (i = 0; i < 4; ++i) {
if (tps->curr_vset_vsel[tps->lru_index[i]] == req_vsel) {
new_vset_reg = tps->lru_index[i];
@@ -117,7 +118,7 @@ update_lru_index:
return found;
}
-static int tps62360_dcdc_get_voltage(struct regulator_dev *dev)
+static int tps62360_dcdc_get_voltage_sel(struct regulator_dev *dev)
{
struct tps62360_chip *tps = rdev_get_drvdata(dev);
int vsel;
@@ -126,12 +127,12 @@ static int tps62360_dcdc_get_voltage(struct regulator_dev *dev)
ret = regmap_read(tps->regmap, REG_VSET0 + tps->curr_vset_id, &data);
if (ret < 0) {
- dev_err(tps->dev, "%s: Error in reading register %d\n",
- __func__, REG_VSET0 + tps->curr_vset_id);
+ dev_err(tps->dev, "%s(): register %d read failed with err %d\n",
+ __func__, REG_VSET0 + tps->curr_vset_id, ret);
return ret;
}
vsel = (int)data & tps->voltage_reg_mask;
- return (tps->voltage_base + vsel * 10) * 1000;
+ return vsel;
}
static int tps62360_dcdc_set_voltage(struct regulator_dev *dev,
@@ -143,17 +144,13 @@ static int tps62360_dcdc_set_voltage(struct regulator_dev *dev,
bool found = false;
int new_vset_id = tps->curr_vset_id;
- if (max_uV < min_uV)
- return -EINVAL;
-
- if (min_uV >
- ((tps->voltage_base + (tps->desc.n_voltages - 1) * 10) * 1000))
+ if ((max_uV < min_uV) || (max_uV < tps->voltage_base))
return -EINVAL;
- if (max_uV < tps->voltage_base * 1000)
+ if (min_uV > (tps->voltage_base + (tps->desc.n_voltages - 1) * 10000))
return -EINVAL;
- vsel = DIV_ROUND_UP(min_uV - (tps->voltage_base * 1000), 10000);
+ vsel = DIV_ROUND_UP(min_uV - tps->voltage_base, 10000);
if (selector)
*selector = (vsel & tps->voltage_reg_mask);
@@ -168,8 +165,9 @@ static int tps62360_dcdc_set_voltage(struct regulator_dev *dev,
ret = regmap_update_bits(tps->regmap, REG_VSET0 + new_vset_id,
tps->voltage_reg_mask, vsel);
if (ret < 0) {
- dev_err(tps->dev, "%s: Error in updating register %d\n",
- __func__, REG_VSET0 + new_vset_id);
+ dev_err(tps->dev,
+ "%s(): register %d update failed with err %d\n",
+ __func__, REG_VSET0 + new_vset_id, ret);
return ret;
}
tps->curr_vset_id = new_vset_id;
@@ -178,8 +176,7 @@ static int tps62360_dcdc_set_voltage(struct regulator_dev *dev,
/* Select proper VSET register vio gpios */
if (tps->valid_gpios) {
- gpio_set_value_cansleep(tps->vsel0_gpio,
- new_vset_id & 0x1);
+ gpio_set_value_cansleep(tps->vsel0_gpio, new_vset_id & 0x1);
gpio_set_value_cansleep(tps->vsel1_gpio,
(new_vset_id >> 1) & 0x1);
}
@@ -191,82 +188,146 @@ static int tps62360_dcdc_list_voltage(struct regulator_dev *dev,
{
struct tps62360_chip *tps = rdev_get_drvdata(dev);
- if ((selector < 0) || (selector >= tps->desc.n_voltages))
+ if (selector >= tps->desc.n_voltages)
return -EINVAL;
- return (tps->voltage_base + selector * 10) * 1000;
+
+ return tps->voltage_base + selector * 10000;
}
-static struct regulator_ops tps62360_dcdc_ops = {
- .get_voltage = tps62360_dcdc_get_voltage,
- .set_voltage = tps62360_dcdc_set_voltage,
- .list_voltage = tps62360_dcdc_list_voltage,
-};
+static int tps62360_set_voltage_time_sel(struct regulator_dev *rdev,
+ unsigned int old_selector, unsigned int new_selector)
+{
+ struct tps62360_chip *tps = rdev_get_drvdata(rdev);
+ int old_uV, new_uV;
-static int tps62360_init_force_pwm(struct tps62360_chip *tps,
- struct tps62360_regulator_platform_data *pdata,
- int vset_id)
+ old_uV = tps62360_dcdc_list_voltage(rdev, old_selector);
+ if (old_uV < 0)
+ return old_uV;
+
+ new_uV = tps62360_dcdc_list_voltage(rdev, new_selector);
+ if (new_uV < 0)
+ return new_uV;
+
+ return DIV_ROUND_UP(abs(old_uV - new_uV), tps->change_uv_per_us);
+}
+
+static int tps62360_set_mode(struct regulator_dev *rdev, unsigned int mode)
{
+ struct tps62360_chip *tps = rdev_get_drvdata(rdev);
+ int i;
+ int val;
+ int ret;
+
+ /* Enable force PWM mode in FAST mode only. */
+ switch (mode) {
+ case REGULATOR_MODE_FAST:
+ val = FORCE_PWM_ENABLE;
+ break;
+
+ case REGULATOR_MODE_NORMAL:
+ val = 0;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (!tps->valid_gpios) {
+ ret = regmap_update_bits(tps->regmap,
+ REG_VSET0 + tps->curr_vset_id, FORCE_PWM_ENABLE, val);
+ if (ret < 0)
+ dev_err(tps->dev,
+ "%s(): register %d update failed with err %d\n",
+ __func__, REG_VSET0 + tps->curr_vset_id, ret);
+ return ret;
+ }
+
+ /* If gpios are valid then all register set need to be control */
+ for (i = 0; i < 4; ++i) {
+ ret = regmap_update_bits(tps->regmap,
+ REG_VSET0 + i, FORCE_PWM_ENABLE, val);
+ if (ret < 0) {
+ dev_err(tps->dev,
+ "%s(): register %d update failed with err %d\n",
+ __func__, REG_VSET0 + i, ret);
+ return ret;
+ }
+ }
+ return ret;
+}
+
+static unsigned int tps62360_get_mode(struct regulator_dev *rdev)
+{
+ struct tps62360_chip *tps = rdev_get_drvdata(rdev);
unsigned int data;
int ret;
- ret = regmap_read(tps->regmap, REG_VSET0 + vset_id, &data);
+
+ ret = regmap_read(tps->regmap, REG_VSET0 + tps->curr_vset_id, &data);
if (ret < 0) {
- dev_err(tps->dev, "%s() fails in writing reg %d\n",
- __func__, REG_VSET0 + vset_id);
+ dev_err(tps->dev, "%s(): register %d read failed with err %d\n",
+ __func__, REG_VSET0 + tps->curr_vset_id, ret);
return ret;
}
- tps->curr_vset_vsel[vset_id] = data & tps->voltage_reg_mask;
- if (pdata->en_force_pwm)
- data |= BIT(7);
- else
- data &= ~BIT(7);
- ret = regmap_write(tps->regmap, REG_VSET0 + vset_id, data);
- if (ret < 0)
- dev_err(tps->dev, "%s() fails in writing reg %d\n",
- __func__, REG_VSET0 + vset_id);
- return ret;
+ return (data & FORCE_PWM_ENABLE) ?
+ REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL;
}
-static int tps62360_init_dcdc(struct tps62360_chip *tps,
+static struct regulator_ops tps62360_dcdc_ops = {
+ .get_voltage_sel = tps62360_dcdc_get_voltage_sel,
+ .set_voltage = tps62360_dcdc_set_voltage,
+ .list_voltage = tps62360_dcdc_list_voltage,
+ .set_voltage_time_sel = tps62360_set_voltage_time_sel,
+ .set_mode = tps62360_set_mode,
+ .get_mode = tps62360_get_mode,
+};
+
+static int __devinit tps62360_init_dcdc(struct tps62360_chip *tps,
struct tps62360_regulator_platform_data *pdata)
{
int ret;
- int i;
+ unsigned int ramp_ctrl;
- /* Initailize internal pull up/down control */
+ /* Initialize internal pull up/down control */
if (tps->en_internal_pulldn)
ret = regmap_write(tps->regmap, REG_CONTROL, 0xE0);
else
ret = regmap_write(tps->regmap, REG_CONTROL, 0x0);
if (ret < 0) {
- dev_err(tps->dev, "%s() fails in writing reg %d\n",
- __func__, REG_CONTROL);
+ dev_err(tps->dev,
+ "%s(): register %d write failed with err %d\n",
+ __func__, REG_CONTROL, ret);
return ret;
}
- /* Initailize force PWM mode */
- if (tps->valid_gpios) {
- for (i = 0; i < 4; ++i) {
- ret = tps62360_init_force_pwm(tps, pdata, i);
- if (ret < 0)
- return ret;
- }
- } else {
- ret = tps62360_init_force_pwm(tps, pdata, tps->curr_vset_id);
- if (ret < 0)
- return ret;
- }
-
/* Reset output discharge path to reduce power consumption */
ret = regmap_update_bits(tps->regmap, REG_RAMPCTRL, BIT(2), 0);
- if (ret < 0)
- dev_err(tps->dev, "%s() fails in updating reg %d\n",
- __func__, REG_RAMPCTRL);
+ if (ret < 0) {
+ dev_err(tps->dev,
+ "%s(): register %d update failed with err %d\n",
+ __func__, REG_RAMPCTRL, ret);
+ return ret;
+ }
+
+ /* Get ramp value from ramp control register */
+ ret = regmap_read(tps->regmap, REG_RAMPCTRL, &ramp_ctrl);
+ if (ret < 0) {
+ dev_err(tps->dev,
+ "%s(): register %d read failed with err %d\n",
+ __func__, REG_RAMPCTRL, ret);
+ return ret;
+ }
+ ramp_ctrl = (ramp_ctrl >> 4) & 0x7;
+
+ /* ramp mV/us = 32/(2^ramp_ctrl) */
+ tps->change_uv_per_us = DIV_ROUND_UP(32000, BIT(ramp_ctrl));
return ret;
}
static const struct regmap_config tps62360_regmap_config = {
- .reg_bits = 8,
- .val_bits = 8,
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = REG_CHIPID,
+ .cache_type = REGCACHE_RBTREE,
};
static int __devinit tps62360_probe(struct i2c_client *client,
@@ -280,42 +341,52 @@ static int __devinit tps62360_probe(struct i2c_client *client,
pdata = client->dev.platform_data;
if (!pdata) {
- dev_err(&client->dev, "%s() Err: Platform data not found\n",
+ dev_err(&client->dev, "%s(): Platform data not found\n",
__func__);
return -EIO;
}
tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
if (!tps) {
- dev_err(&client->dev, "%s() Err: Memory allocation fails\n",
+ dev_err(&client->dev, "%s(): Memory allocation failed\n",
__func__);
return -ENOMEM;
}
- tps->en_force_pwm = pdata->en_force_pwm;
tps->en_discharge = pdata->en_discharge;
tps->en_internal_pulldn = pdata->en_internal_pulldn;
tps->vsel0_gpio = pdata->vsel0_gpio;
tps->vsel1_gpio = pdata->vsel1_gpio;
- tps->client = client;
tps->dev = &client->dev;
- tps->name = id->name;
- tps->voltage_base = (id->driver_data == TPS62360) ?
- TPS62360_BASE_VOLTAGE : TPS62361_BASE_VOLTAGE;
- tps->voltage_reg_mask = (id->driver_data == TPS62360) ? 0x3F : 0x7F;
+
+ switch (id->driver_data) {
+ case TPS62360:
+ case TPS62362:
+ tps->voltage_base = TPS62360_BASE_VOLTAGE;
+ tps->voltage_reg_mask = 0x3F;
+ tps->desc.n_voltages = TPS62360_N_VOLTAGES;
+ break;
+ case TPS62361:
+ case TPS62363:
+ tps->voltage_base = TPS62361_BASE_VOLTAGE;
+ tps->voltage_reg_mask = 0x7F;
+ tps->desc.n_voltages = TPS62361_N_VOLTAGES;
+ break;
+ default:
+ return -ENODEV;
+ }
tps->desc.name = id->name;
tps->desc.id = 0;
- tps->desc.n_voltages = (id->driver_data == TPS62360) ?
- TPS62360_N_VOLTAGES : TPS62361_N_VOLTAGES;
tps->desc.ops = &tps62360_dcdc_ops;
tps->desc.type = REGULATOR_VOLTAGE;
tps->desc.owner = THIS_MODULE;
- tps->regmap = regmap_init_i2c(client, &tps62360_regmap_config);
+ tps->regmap = devm_regmap_init_i2c(client, &tps62360_regmap_config);
if (IS_ERR(tps->regmap)) {
ret = PTR_ERR(tps->regmap);
- dev_err(&client->dev, "%s() Err: Failed to allocate register"
- "map: %d\n", __func__, ret);
+ dev_err(&client->dev,
+ "%s(): regmap allocation failed with err %d\n",
+ __func__, ret);
return ret;
}
i2c_set_clientdata(client, tps);
@@ -326,35 +397,26 @@ static int __devinit tps62360_probe(struct i2c_client *client,
tps->valid_gpios = false;
if (gpio_is_valid(tps->vsel0_gpio) && gpio_is_valid(tps->vsel1_gpio)) {
- ret = gpio_request(tps->vsel0_gpio, "tps62360-vsel0");
+ int gpio_flags;
+ gpio_flags = (pdata->vsel0_def_state) ?
+ GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
+ ret = gpio_request_one(tps->vsel0_gpio,
+ gpio_flags, "tps62360-vsel0");
if (ret) {
dev_err(&client->dev,
- "Err: Could not obtain vsel0 GPIO %d: %d\n",
- tps->vsel0_gpio, ret);
- goto err_gpio0;
- }
- ret = gpio_direction_output(tps->vsel0_gpio,
- pdata->vsel0_def_state);
- if (ret) {
- dev_err(&client->dev, "Err: Could not set direction of"
- "vsel0 GPIO %d: %d\n", tps->vsel0_gpio, ret);
- gpio_free(tps->vsel0_gpio);
+ "%s(): Could not obtain vsel0 GPIO %d: %d\n",
+ __func__, tps->vsel0_gpio, ret);
goto err_gpio0;
}
- ret = gpio_request(tps->vsel1_gpio, "tps62360-vsel1");
+ gpio_flags = (pdata->vsel1_def_state) ?
+ GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
+ ret = gpio_request_one(tps->vsel1_gpio,
+ gpio_flags, "tps62360-vsel1");
if (ret) {
dev_err(&client->dev,
- "Err: Could not obtain vsel1 GPIO %d: %d\n",
- tps->vsel1_gpio, ret);
- goto err_gpio1;
- }
- ret = gpio_direction_output(tps->vsel1_gpio,
- pdata->vsel1_def_state);
- if (ret) {
- dev_err(&client->dev, "Err: Could not set direction of"
- "vsel1 GPIO %d: %d\n", tps->vsel1_gpio, ret);
- gpio_free(tps->vsel1_gpio);
+ "%s(): Could not obtain vsel1 GPIO %d: %d\n",
+ __func__, tps->vsel1_gpio, ret);
goto err_gpio1;
}
tps->valid_gpios = true;
@@ -371,7 +433,7 @@ static int __devinit tps62360_probe(struct i2c_client *client,
ret = tps62360_init_dcdc(tps, pdata);
if (ret < 0) {
- dev_err(tps->dev, "%s() Err: Init fails with = %d\n",
+ dev_err(tps->dev, "%s(): Init failed with err = %d\n",
__func__, ret);
goto err_init;
}
@@ -380,8 +442,9 @@ static int __devinit tps62360_probe(struct i2c_client *client,
rdev = regulator_register(&tps->desc, &client->dev,
&pdata->reg_init_data, tps);
if (IS_ERR(rdev)) {
- dev_err(tps->dev, "%s() Err: Failed to register %s\n",
- __func__, id->name);
+ dev_err(tps->dev,
+ "%s(): regulator register failed with err %s\n",
+ __func__, id->name);
ret = PTR_ERR(rdev);
goto err_init;
}
@@ -396,7 +459,6 @@ err_gpio1:
if (gpio_is_valid(tps->vsel0_gpio))
gpio_free(tps->vsel0_gpio);
err_gpio0:
- regmap_exit(tps->regmap);
return ret;
}
@@ -417,7 +479,6 @@ static int __devexit tps62360_remove(struct i2c_client *client)
gpio_free(tps->vsel0_gpio);
regulator_unregister(tps->rdev);
- regmap_exit(tps->regmap);
return 0;
}
@@ -432,13 +493,16 @@ static void tps62360_shutdown(struct i2c_client *client)
/* Configure the output discharge path */
st = regmap_update_bits(tps->regmap, REG_RAMPCTRL, BIT(2), BIT(2));
if (st < 0)
- dev_err(tps->dev, "%s() fails in updating reg %d\n",
- __func__, REG_RAMPCTRL);
+ dev_err(tps->dev,
+ "%s(): register %d update failed with err %d\n",
+ __func__, REG_RAMPCTRL, st);
}
static const struct i2c_device_id tps62360_id[] = {
{.name = "tps62360", .driver_data = TPS62360},
{.name = "tps62361", .driver_data = TPS62361},
+ {.name = "tps62362", .driver_data = TPS62362},
+ {.name = "tps62363", .driver_data = TPS62363},
{},
};
@@ -468,5 +532,5 @@ static void __exit tps62360_cleanup(void)
module_exit(tps62360_cleanup);
MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
-MODULE_DESCRIPTION("TPS62360 voltage regulator driver");
+MODULE_DESCRIPTION("TPS6236x voltage regulator driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/tps6238x0-regulator.c b/drivers/regulator/tps6238x0-regulator.c
new file mode 100644
index 000000000000..611b9425a263
--- /dev/null
+++ b/drivers/regulator/tps6238x0-regulator.c
@@ -0,0 +1,470 @@
+/*
+ * tps6238x0-regulator.c -- TI tps623850/tps623860/tps623870
+ *
+ * Driver for processor core supply tps623850, tps623860 and tps623870
+ *
+ * Copyright (c) 2012, NVIDIA Corporation.
+ *
+ * Author: Laxman Dewangan <ldewangan@nvidia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * 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.
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/tps6238x0-regulator.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+
+/* Register definitions */
+#define REG_VSET0 0
+#define REG_VSET1 1
+#define REG_MODE0 2
+#define REG_MODE1 3
+#define REG_CONTROL 4
+#define REG_EXCEPTION 5
+#define REG_RAMPCTRL 6
+#define REG_IOUT 7
+#define REG_CHIPID 8
+
+#define TPS6238X0_BASE_VOLTAGE 500000
+#define TPS6238X0_N_VOLTAGES 128
+#define TPS6238X0_MAX_VSET 2
+#define TPS6238X0_VOUT_MASK 0x7F
+
+/* tps 6238x0 chip information */
+struct tps6238x0_chip {
+ const char *name;
+ struct device *dev;
+ struct regulator_desc desc;
+ struct regulator_dev *rdev;
+ struct regmap *regmap;
+ int vsel_gpio;
+ int change_uv_per_us;
+ bool en_internal_pulldn;
+ bool valid_gpios;
+ int lru_index[TPS6238X0_MAX_VSET];
+ int curr_vset_vsel[TPS6238X0_MAX_VSET];
+ int curr_vset_id;
+};
+
+/*
+ * find_voltage_set_register: Find new voltage configuration register
+ * (VSET) id.
+ * The finding of the new VSET register will be based on the LRU mechanism.
+ * Each VSET register will have different voltage configured . This
+ * Function will look if any of the VSET register have requested voltage set
+ * or not.
+ * - If it is already there then it will make that register as most
+ * recently used and return as found so that caller need not to set
+ * the VSET register but need to set the proper gpios to select this
+ * VSET register.
+ * - If requested voltage is not found then it will use the least
+ * recently mechanism to get new VSET register for new configuration
+ * and will return not_found so that caller need to set new VSET
+ * register and then gpios (both).
+ */
+static bool find_voltage_set_register(struct tps6238x0_chip *tps,
+ int req_vsel, int *vset_reg_id)
+{
+ int i;
+ bool found = false;
+ int new_vset_reg = tps->lru_index[1];
+ int found_index = 1;
+ for (i = 0; i < TPS6238X0_MAX_VSET; ++i) {
+ if (tps->curr_vset_vsel[tps->lru_index[i]] == req_vsel) {
+ new_vset_reg = tps->lru_index[i];
+ found_index = i;
+ found = true;
+ goto update_lru_index;
+ }
+ }
+
+update_lru_index:
+ for (i = found_index; i > 0; i--)
+ tps->lru_index[i] = tps->lru_index[i - 1];
+
+ tps->lru_index[0] = new_vset_reg;
+ *vset_reg_id = new_vset_reg;
+ return found;
+}
+
+static int tps6238x0_get_voltage_sel(struct regulator_dev *dev)
+{
+ struct tps6238x0_chip *tps = rdev_get_drvdata(dev);
+ unsigned int data;
+ int ret;
+
+ ret = regmap_read(tps->regmap, REG_VSET0 + tps->curr_vset_id, &data);
+ if (ret < 0) {
+ dev_err(tps->dev, "%s: Error in reading register %d\n",
+ __func__, REG_VSET0 + tps->curr_vset_id);
+ return ret;
+ }
+ return data & TPS6238X0_VOUT_MASK;
+}
+
+static int tps6238x0_set_voltage(struct regulator_dev *dev,
+ int min_uV, int max_uV, unsigned *selector)
+{
+ struct tps6238x0_chip *tps = rdev_get_drvdata(dev);
+ int vsel;
+ int ret;
+ bool found = false;
+ int new_vset_id = tps->curr_vset_id;
+
+ if (min_uV >
+ ((TPS6238X0_BASE_VOLTAGE + (TPS6238X0_N_VOLTAGES - 1) * 10000)))
+ return -EINVAL;
+
+ if ((max_uV < min_uV) || (max_uV < TPS6238X0_BASE_VOLTAGE))
+ return -EINVAL;
+
+ vsel = DIV_ROUND_UP(min_uV - TPS6238X0_BASE_VOLTAGE, 10000);
+ if (selector)
+ *selector = (vsel & TPS6238X0_VOUT_MASK);
+
+ /*
+ * If gpios are available to select the VSET register then least
+ * recently used register for new configuration.
+ */
+ if (tps->valid_gpios)
+ found = find_voltage_set_register(tps, vsel, &new_vset_id);
+
+ if (!found) {
+ ret = regmap_update_bits(tps->regmap, REG_VSET0 + new_vset_id,
+ TPS6238X0_VOUT_MASK, vsel);
+ if (ret < 0) {
+ dev_err(tps->dev, "%s: Error in updating register %d\n",
+ __func__, REG_VSET0 + new_vset_id);
+ return ret;
+ }
+ tps->curr_vset_id = new_vset_id;
+ tps->curr_vset_vsel[new_vset_id] = vsel;
+ }
+
+ /* Select proper VSET register vio gpios */
+ if (tps->valid_gpios)
+ gpio_set_value_cansleep(tps->vsel_gpio, new_vset_id & 0x1);
+ return 0;
+}
+
+static int tps6238x0_list_voltage(struct regulator_dev *dev,
+ unsigned selector)
+{
+ struct tps6238x0_chip *tps = rdev_get_drvdata(dev);
+
+ if ((selector < 0) || (selector >= tps->desc.n_voltages))
+ return -EINVAL;
+
+ return TPS6238X0_BASE_VOLTAGE + selector * 10000;
+}
+
+static int tps6238x0_regulator_enable_time(struct regulator_dev *rdev)
+{
+ return 300;
+}
+
+static int tps6238x0_set_voltage_time_sel(struct regulator_dev *rdev,
+ unsigned int old_selector, unsigned int new_selector)
+{
+ struct tps6238x0_chip *tps = rdev_get_drvdata(rdev);
+ int old_uV, new_uV;
+ old_uV = tps6238x0_list_voltage(rdev, old_selector);
+
+ if (old_uV < 0)
+ return old_uV;
+
+ new_uV = tps6238x0_list_voltage(rdev, new_selector);
+ if (new_uV < 0)
+ return new_uV;
+
+ return DIV_ROUND_UP(abs(old_uV - new_uV),
+ tps->change_uv_per_us);
+}
+
+static int tps6238x0_is_enable(struct regulator_dev *rdev)
+{
+ struct tps6238x0_chip *tps = rdev_get_drvdata(rdev);
+ unsigned int data;
+ int ret;
+
+ ret = regmap_read(tps->regmap, REG_VSET0 + tps->curr_vset_id, &data);
+ if (ret < 0) {
+ dev_err(tps->dev, "%s: Error in reading register %d\n",
+ __func__, REG_VSET0 + tps->curr_vset_id);
+ return ret;
+ }
+ return !!(data & BIT(7));
+}
+
+static int tps6238x0_enable(struct regulator_dev *rdev)
+{
+ struct tps6238x0_chip *tps = rdev_get_drvdata(rdev);
+ int ret;
+ int i;
+
+ /* Enable required VSET configuration */
+ for (i = 0; i < TPS6238X0_MAX_VSET; ++i) {
+ unsigned int en = 0;
+ if (tps->valid_gpios || (i == tps->curr_vset_id))
+ en = BIT(7);
+
+ ret = regmap_update_bits(tps->regmap, REG_VSET0 + i,
+ BIT(7), en);
+ if (ret < 0) {
+ dev_err(tps->dev, "%s() fails in updating reg %d\n",
+ __func__, REG_VSET0 + i);
+ return ret;
+ }
+ }
+ return ret;
+}
+
+static int tps6238x0_disable(struct regulator_dev *rdev)
+{
+ struct tps6238x0_chip *tps = rdev_get_drvdata(rdev);
+ int ret;
+ int i;
+
+ /* Disable required VSET configuration */
+ for (i = 0; i < TPS6238X0_MAX_VSET; ++i) {
+ ret = regmap_update_bits(tps->regmap, REG_VSET0 + i,
+ BIT(7), 0);
+ if (ret < 0) {
+ dev_err(tps->dev, "%s() fails in updating reg %d\n",
+ __func__, REG_VSET0 + i);
+ return ret;
+ }
+ }
+ return ret;
+}
+
+static struct regulator_ops tps6238x0_ops = {
+ .is_enabled = tps6238x0_is_enable,
+ .enable = tps6238x0_enable,
+ .disable = tps6238x0_disable,
+ .enable_time = tps6238x0_regulator_enable_time,
+ .set_voltage_time_sel = tps6238x0_set_voltage_time_sel,
+ .get_voltage_sel = tps6238x0_get_voltage_sel,
+ .set_voltage = tps6238x0_set_voltage,
+ .list_voltage = tps6238x0_list_voltage,
+};
+
+static int __devinit tps6238x0_configure(struct tps6238x0_chip *tps,
+ struct tps6238x0_regulator_platform_data *pdata)
+{
+ int ret;
+ int i;
+
+ /* Initailize internal pull up/down control */
+ if (tps->en_internal_pulldn)
+ ret = regmap_write(tps->regmap, REG_CONTROL, 0xC0);
+ else
+ ret = regmap_write(tps->regmap, REG_CONTROL, 0x0);
+ if (ret < 0) {
+ dev_err(tps->dev, "%s() fails in writing reg %d\n",
+ __func__, REG_CONTROL);
+ return ret;
+ }
+
+ /* Enable required VSET configuration */
+ for (i = 0; i < TPS6238X0_MAX_VSET; ++i) {
+ unsigned int en = 0;
+ if (tps->valid_gpios || (i == tps->curr_vset_id))
+ en = BIT(7);
+
+ ret = regmap_update_bits(tps->regmap, REG_VSET0 + i,
+ BIT(7), en);
+ if (ret < 0) {
+ dev_err(tps->dev, "%s() fails in updating reg %d\n",
+ __func__, REG_VSET0 + i);
+ return ret;
+ }
+ }
+
+ /* Enable output discharge path to have faster discharge */
+ ret = regmap_update_bits(tps->regmap, REG_RAMPCTRL, BIT(2), BIT(2));
+ if (ret < 0)
+ dev_err(tps->dev, "%s() fails in updating reg %d\n",
+ __func__, REG_RAMPCTRL);
+ tps->change_uv_per_us = 312;
+ return ret;
+}
+
+static const struct regmap_config tps6238x0_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = REG_CHIPID,
+ .num_reg_defaults_raw = REG_CHIPID + 1,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static int __devinit tps6238x0_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct tps6238x0_regulator_platform_data *pdata;
+ struct regulator_dev *rdev;
+ struct tps6238x0_chip *tps;
+ int ret;
+ int i;
+
+ pdata = client->dev.platform_data;
+ if (!pdata) {
+ dev_err(&client->dev, "%s() Err: Platform data not found\n",
+ __func__);
+ return -EIO;
+ }
+
+ tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
+ if (!tps) {
+ dev_err(&client->dev, "%s() Err: Memory allocation fails\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ tps->en_internal_pulldn = pdata->en_internal_pulldn;
+ tps->vsel_gpio = pdata->vsel_gpio;
+ tps->dev = &client->dev;
+
+ tps->desc.name = id->name;
+ tps->desc.id = 0;
+ tps->desc.n_voltages = TPS6238X0_N_VOLTAGES;
+ tps->desc.ops = &tps6238x0_ops;
+ tps->desc.type = REGULATOR_VOLTAGE;
+ tps->desc.owner = THIS_MODULE;
+ tps->regmap = devm_regmap_init_i2c(client, &tps6238x0_regmap_config);
+ if (IS_ERR(tps->regmap)) {
+ ret = PTR_ERR(tps->regmap);
+ dev_err(&client->dev, "%s() Err: Failed to allocate register"
+ "map: %d\n", __func__, ret);
+ return ret;
+ }
+ i2c_set_clientdata(client, tps);
+
+ tps->curr_vset_id = (pdata->vsel_def_state & 1);
+ tps->lru_index[0] = tps->curr_vset_id;
+ tps->valid_gpios = false;
+
+ if (gpio_is_valid(tps->vsel_gpio)) {
+ int gpio_flag;
+ gpio_flag = (tps->curr_vset_id) ?
+ GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
+ ret = gpio_request_one(tps->vsel_gpio,
+ gpio_flag, "tps6238x0-vsel0");
+ if (ret) {
+ dev_err(&client->dev,
+ "Err: Could not obtain vsel GPIO %d: %d\n",
+ tps->vsel_gpio, ret);
+ return ret;
+ }
+ tps->valid_gpios = true;
+
+ /*
+ * Initialize the lru index with vset_reg id
+ * The index 0 will be most recently used and
+ * set with the tps->curr_vset_id */
+ for (i = 0; i < TPS6238X0_MAX_VSET; ++i)
+ tps->lru_index[i] = i;
+ tps->lru_index[0] = tps->curr_vset_id;
+ tps->lru_index[tps->curr_vset_id] = 0;
+ }
+
+ ret = tps6238x0_configure(tps, pdata);
+ if (ret < 0) {
+ dev_err(tps->dev, "%s() Err: Init fails with = %d\n",
+ __func__, ret);
+ goto err_init;
+ }
+
+ /* Register the regulators */
+ rdev = regulator_register(&tps->desc, &client->dev,
+ pdata->init_data, tps);
+ if (IS_ERR(rdev)) {
+ dev_err(tps->dev, "%s() Err: Failed to register %s\n",
+ __func__, id->name);
+ ret = PTR_ERR(rdev);
+ goto err_init;
+ }
+
+ tps->rdev = rdev;
+ return 0;
+
+err_init:
+ if (gpio_is_valid(tps->vsel_gpio))
+ gpio_free(tps->vsel_gpio);
+
+ return ret;
+}
+
+/**
+ * tps6238x0_remove - tps62360 driver i2c remove handler
+ * @client: i2c driver client device structure
+ *
+ * Unregister TPS driver as an i2c client device driver
+ */
+static int __devexit tps6238x0_remove(struct i2c_client *client)
+{
+ struct tps6238x0_chip *tps = i2c_get_clientdata(client);
+
+ if (gpio_is_valid(tps->vsel_gpio))
+ gpio_free(tps->vsel_gpio);
+
+ regulator_unregister(tps->rdev);
+ return 0;
+}
+
+static const struct i2c_device_id tps6238x0_id[] = {
+ {.name = "tps623850", },
+ {.name = "tps623860", },
+ {.name = "tps623870", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, tps6238x0_id);
+
+static struct i2c_driver tps6238x0_i2c_driver = {
+ .driver = {
+ .name = "tps6238x0",
+ .owner = THIS_MODULE,
+ },
+ .probe = tps6238x0_probe,
+ .remove = __devexit_p(tps6238x0_remove),
+ .id_table = tps6238x0_id,
+};
+
+static int __init tps6238x0_init(void)
+{
+ return i2c_add_driver(&tps6238x0_i2c_driver);
+}
+subsys_initcall(tps6238x0_init);
+
+static void __exit tps6238x0_cleanup(void)
+{
+ i2c_del_driver(&tps6238x0_i2c_driver);
+}
+module_exit(tps6238x0_cleanup);
+
+MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
+MODULE_DESCRIPTION("TPS623850/TPS623860/TPS623870 voltage regulator driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c
index fe2f1a8412b7..a2fef3880065 100644
--- a/drivers/regulator/tps65910-regulator.c
+++ b/drivers/regulator/tps65910-regulator.c
@@ -331,21 +331,16 @@ struct tps65910_reg {
static inline int tps65910_read(struct tps65910_reg *pmic, u8 reg)
{
- u8 val;
+ unsigned int val;
int err;
- err = pmic->mfd->read(pmic->mfd, reg, 1, &val);
+ err = tps65910_reg_read(pmic->mfd, reg, &val);
if (err)
return err;
return val;
}
-static inline int tps65910_write(struct tps65910_reg *pmic, u8 reg, u8 val)
-{
- return pmic->mfd->write(pmic->mfd, reg, 1, &val);
-}
-
static int tps65910_modify_bits(struct tps65910_reg *pmic, u8 reg,
u8 set_mask, u8 clear_mask)
{
@@ -362,7 +357,7 @@ static int tps65910_modify_bits(struct tps65910_reg *pmic, u8 reg,
data &= ~clear_mask;
data |= set_mask;
- err = tps65910_write(pmic, reg, data);
+ err = tps65910_reg_write(pmic->mfd, reg, data);
if (err)
dev_err(pmic->mfd->dev, "Write for reg 0x%x failed\n", reg);
@@ -371,7 +366,7 @@ out:
return err;
}
-static int tps65910_reg_read(struct tps65910_reg *pmic, u8 reg)
+static int tps65910_reg_read_locked(struct tps65910_reg *pmic, u8 reg)
{
int data;
@@ -385,13 +380,13 @@ static int tps65910_reg_read(struct tps65910_reg *pmic, u8 reg)
return data;
}
-static int tps65910_reg_write(struct tps65910_reg *pmic, u8 reg, u8 val)
+static int tps65910_reg_write_locked(struct tps65910_reg *pmic, u8 reg, u8 val)
{
int err;
mutex_lock(&pmic->mutex);
- err = tps65910_write(pmic, reg, val);
+ err = tps65910_reg_write(pmic->mfd, reg, val);
if (err < 0)
dev_err(pmic->mfd->dev, "Write for reg 0x%x failed\n", reg);
@@ -476,7 +471,7 @@ static int tps65910_is_enabled(struct regulator_dev *dev)
if (reg < 0)
return reg;
- value = tps65910_reg_read(pmic, reg);
+ value = tps65910_reg_read_locked(pmic, reg);
if (value < 0)
return value;
@@ -493,7 +488,7 @@ static int tps65910_enable(struct regulator_dev *dev)
if (reg < 0)
return reg;
- return tps65910_set_bits(mfd, reg, TPS65910_SUPPLY_STATE_ENABLED);
+ return tps65910_reg_set_bits(mfd, reg, TPS65910_SUPPLY_STATE_ENABLED);
}
static int tps65910_disable(struct regulator_dev *dev)
@@ -506,7 +501,7 @@ static int tps65910_disable(struct regulator_dev *dev)
if (reg < 0)
return reg;
- return tps65910_clear_bits(mfd, reg, TPS65910_SUPPLY_STATE_ENABLED);
+ return tps65910_reg_clear_bits(mfd, reg, TPS65910_SUPPLY_STATE_ENABLED);
}
static int tps65910_enable_time(struct regulator_dev *dev)
@@ -532,9 +527,9 @@ static int tps65910_set_mode(struct regulator_dev *dev, unsigned int mode)
LDO_ST_MODE_BIT);
case REGULATOR_MODE_IDLE:
value = LDO_ST_ON_BIT | LDO_ST_MODE_BIT;
- return tps65910_set_bits(mfd, reg, value);
+ return tps65910_reg_set_bits(mfd, reg, value);
case REGULATOR_MODE_STANDBY:
- return tps65910_clear_bits(mfd, reg, LDO_ST_ON_BIT);
+ return tps65910_reg_clear_bits(mfd, reg, LDO_ST_ON_BIT);
}
return -EINVAL;
@@ -549,7 +544,7 @@ static unsigned int tps65910_get_mode(struct regulator_dev *dev)
if (reg < 0)
return reg;
- value = tps65910_reg_read(pmic, reg);
+ value = tps65910_reg_read_locked(pmic, reg);
if (value < 0)
return value;
@@ -569,28 +564,28 @@ static int tps65910_get_voltage_dcdc_sel(struct regulator_dev *dev)
switch (id) {
case TPS65910_REG_VDD1:
- opvsel = tps65910_reg_read(pmic, TPS65910_VDD1_OP);
- mult = tps65910_reg_read(pmic, TPS65910_VDD1);
+ opvsel = tps65910_reg_read_locked(pmic, TPS65910_VDD1_OP);
+ mult = tps65910_reg_read_locked(pmic, TPS65910_VDD1);
mult = (mult & VDD1_VGAIN_SEL_MASK) >> VDD1_VGAIN_SEL_SHIFT;
- srvsel = tps65910_reg_read(pmic, TPS65910_VDD1_SR);
+ srvsel = tps65910_reg_read_locked(pmic, TPS65910_VDD1_SR);
sr = opvsel & VDD1_OP_CMD_MASK;
opvsel &= VDD1_OP_SEL_MASK;
srvsel &= VDD1_SR_SEL_MASK;
vselmax = 75;
break;
case TPS65910_REG_VDD2:
- opvsel = tps65910_reg_read(pmic, TPS65910_VDD2_OP);
- mult = tps65910_reg_read(pmic, TPS65910_VDD2);
+ opvsel = tps65910_reg_read_locked(pmic, TPS65910_VDD2_OP);
+ mult = tps65910_reg_read_locked(pmic, TPS65910_VDD2);
mult = (mult & VDD2_VGAIN_SEL_MASK) >> VDD2_VGAIN_SEL_SHIFT;
- srvsel = tps65910_reg_read(pmic, TPS65910_VDD2_SR);
+ srvsel = tps65910_reg_read_locked(pmic, TPS65910_VDD2_SR);
sr = opvsel & VDD2_OP_CMD_MASK;
opvsel &= VDD2_OP_SEL_MASK;
srvsel &= VDD2_SR_SEL_MASK;
vselmax = 75;
break;
case TPS65911_REG_VDDCTRL:
- opvsel = tps65910_reg_read(pmic, TPS65911_VDDCTRL_OP);
- srvsel = tps65910_reg_read(pmic, TPS65911_VDDCTRL_SR);
+ opvsel = tps65910_reg_read_locked(pmic, TPS65911_VDDCTRL_OP);
+ srvsel = tps65910_reg_read_locked(pmic, TPS65911_VDDCTRL_SR);
sr = opvsel & VDDCTRL_OP_CMD_MASK;
opvsel &= VDDCTRL_OP_SEL_MASK;
srvsel &= VDDCTRL_SR_SEL_MASK;
@@ -630,7 +625,7 @@ static int tps65910_get_voltage(struct regulator_dev *dev)
if (reg < 0)
return reg;
- value = tps65910_reg_read(pmic, reg);
+ value = tps65910_reg_read_locked(pmic, reg);
if (value < 0)
return value;
@@ -669,7 +664,7 @@ static int tps65911_get_voltage(struct regulator_dev *dev)
reg = pmic->get_ctrl_reg(id);
- value = tps65910_reg_read(pmic, reg);
+ value = tps65910_reg_read_locked(pmic, reg);
switch (id) {
case TPS65911_REG_LDO1:
@@ -728,7 +723,7 @@ static int tps65910_set_voltage_dcdc_sel(struct regulator_dev *dev,
tps65910_modify_bits(pmic, TPS65910_VDD1,
(dcdc_mult << VDD1_VGAIN_SEL_SHIFT),
VDD1_VGAIN_SEL_MASK);
- tps65910_reg_write(pmic, TPS65910_VDD1_OP, vsel);
+ tps65910_reg_write_locked(pmic, TPS65910_VDD1_OP, vsel);
break;
case TPS65910_REG_VDD2:
dcdc_mult = (selector / VDD1_2_NUM_VOLT_FINE) + 1;
@@ -739,11 +734,11 @@ static int tps65910_set_voltage_dcdc_sel(struct regulator_dev *dev,
tps65910_modify_bits(pmic, TPS65910_VDD2,
(dcdc_mult << VDD2_VGAIN_SEL_SHIFT),
VDD1_VGAIN_SEL_MASK);
- tps65910_reg_write(pmic, TPS65910_VDD2_OP, vsel);
+ tps65910_reg_write_locked(pmic, TPS65910_VDD2_OP, vsel);
break;
case TPS65911_REG_VDDCTRL:
vsel = selector + 3;
- tps65910_reg_write(pmic, TPS65911_VDDCTRL_OP, vsel);
+ tps65910_reg_write_locked(pmic, TPS65911_VDDCTRL_OP, vsel);
}
return 0;
@@ -994,10 +989,10 @@ static int tps65910_set_ext_sleep_config(struct tps65910_reg *pmic,
/* External EN1 control */
if (ext_sleep_config & TPS65910_SLEEP_CONTROL_EXT_INPUT_EN1)
- ret = tps65910_set_bits(mfd,
+ ret = tps65910_reg_set_bits(mfd,
TPS65910_EN1_LDO_ASS + regoffs, bit_pos);
else
- ret = tps65910_clear_bits(mfd,
+ ret = tps65910_reg_clear_bits(mfd,
TPS65910_EN1_LDO_ASS + regoffs, bit_pos);
if (ret < 0) {
dev_err(mfd->dev,
@@ -1007,10 +1002,10 @@ static int tps65910_set_ext_sleep_config(struct tps65910_reg *pmic,
/* External EN2 control */
if (ext_sleep_config & TPS65910_SLEEP_CONTROL_EXT_INPUT_EN2)
- ret = tps65910_set_bits(mfd,
+ ret = tps65910_reg_set_bits(mfd,
TPS65910_EN2_LDO_ASS + regoffs, bit_pos);
else
- ret = tps65910_clear_bits(mfd,
+ ret = tps65910_reg_clear_bits(mfd,
TPS65910_EN2_LDO_ASS + regoffs, bit_pos);
if (ret < 0) {
dev_err(mfd->dev,
@@ -1022,10 +1017,10 @@ static int tps65910_set_ext_sleep_config(struct tps65910_reg *pmic,
if ((tps65910_chip_id(mfd) == TPS65910) &&
(id >= TPS65910_REG_VDIG1)) {
if (ext_sleep_config & TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3)
- ret = tps65910_set_bits(mfd,
+ ret = tps65910_reg_set_bits(mfd,
TPS65910_EN3_LDO_ASS + regoffs, bit_pos);
else
- ret = tps65910_clear_bits(mfd,
+ ret = tps65910_reg_clear_bits(mfd,
TPS65910_EN3_LDO_ASS + regoffs, bit_pos);
if (ret < 0) {
dev_err(mfd->dev,
@@ -1037,10 +1032,10 @@ static int tps65910_set_ext_sleep_config(struct tps65910_reg *pmic,
/* Return if no external control is selected */
if (!(ext_sleep_config & EXT_SLEEP_CONTROL)) {
/* Clear all sleep controls */
- ret = tps65910_clear_bits(mfd,
+ ret = tps65910_reg_clear_bits(mfd,
TPS65910_SLEEP_KEEP_LDO_ON + regoffs, bit_pos);
if (!ret)
- ret = tps65910_clear_bits(mfd,
+ ret = tps65910_reg_clear_bits(mfd,
TPS65910_SLEEP_SET_LDO_OFF + regoffs, bit_pos);
if (ret < 0)
dev_err(mfd->dev,
@@ -1059,32 +1054,33 @@ static int tps65910_set_ext_sleep_config(struct tps65910_reg *pmic,
(tps65910_chip_id(mfd) == TPS65911))) {
int op_reg_add = pmic->get_ctrl_reg(id) + 1;
int sr_reg_add = pmic->get_ctrl_reg(id) + 2;
- int opvsel = tps65910_reg_read(pmic, op_reg_add);
- int srvsel = tps65910_reg_read(pmic, sr_reg_add);
+ int opvsel = tps65910_reg_read_locked(pmic, op_reg_add);
+ int srvsel = tps65910_reg_read_locked(pmic, sr_reg_add);
if (opvsel & VDD1_OP_CMD_MASK) {
u8 reg_val = srvsel & VDD1_OP_SEL_MASK;
- ret = tps65910_reg_write(pmic, op_reg_add, reg_val);
+ ret = tps65910_reg_write_locked(pmic, op_reg_add,
+ reg_val);
if (ret < 0) {
dev_err(mfd->dev,
"Error in configuring op register\n");
return ret;
}
}
- ret = tps65910_reg_write(pmic, sr_reg_add, 0);
+ ret = tps65910_reg_write_locked(pmic, sr_reg_add, 0);
if (ret < 0) {
dev_err(mfd->dev, "Error in settting sr register\n");
return ret;
}
}
- ret = tps65910_clear_bits(mfd,
+ ret = tps65910_reg_clear_bits(mfd,
TPS65910_SLEEP_KEEP_LDO_ON + regoffs, bit_pos);
if (!ret) {
if (ext_sleep_config & TPS65911_SLEEP_CONTROL_EXT_INPUT_SLEEP)
- ret = tps65910_set_bits(mfd,
+ ret = tps65910_reg_set_bits(mfd,
TPS65910_SLEEP_SET_LDO_OFF + regoffs, bit_pos);
else
- ret = tps65910_clear_bits(mfd,
+ ret = tps65910_reg_clear_bits(mfd,
TPS65910_SLEEP_SET_LDO_OFF + regoffs, bit_pos);
}
if (ret < 0)
@@ -1117,7 +1113,7 @@ static __devinit int tps65910_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, pmic);
/* Give control of all register to control port */
- tps65910_set_bits(pmic->mfd, TPS65910_DEVCTRL,
+ tps65910_reg_set_bits(pmic->mfd, TPS65910_DEVCTRL,
DEVCTRL_SR_CTL_I2C_SEL_MASK);
switch(tps65910_chip_id(tps65910)) {
diff --git a/drivers/regulator/tps80031-regulator.c b/drivers/regulator/tps80031-regulator.c
index 411b839f1a74..efc608c936ea 100644
--- a/drivers/regulator/tps80031-regulator.c
+++ b/drivers/regulator/tps80031-regulator.c
@@ -100,6 +100,7 @@ struct tps80031_regulator {
/* chip constraints on regulator behavior */
u16 min_mV;
u16 max_mV;
+ unsigned int tolerance_uv;
/* regulator specific turn-on delay */
int delay;
@@ -296,6 +297,8 @@ static int __tps80031_dcdc_set_voltage(struct device *parent,
int vsel = 0;
int ret;
+ min_uV = min_uV - ri->tolerance_uv;
+
switch (ri->flags) {
case 0:
if (min_uV == 0)
@@ -801,11 +804,11 @@ static int tps80031_power_req_config(struct device *parent,
struct tps80031_regulator *ri,
struct tps80031_regulator_platform_data *tps80031_pdata)
{
- int ret;
+ int ret = 0;
uint8_t reg_val;
if (ri->preq_bit < 0)
- return 0;
+ goto skip_pwr_req_config;
ret = tps80031_ext_power_req_config(parent, ri->ext_ctrl_flag,
ri->preq_bit, ri->state_reg, ri->trans_reg);
@@ -821,6 +824,7 @@ static int tps80031_power_req_config(struct device *parent,
return ret;
}
+skip_pwr_req_config:
if (tps80031_pdata->ext_ctrl_flag &
(PWR_OFF_ON_SLEEP | PWR_ON_ON_SLEEP)) {
reg_val = (ri->trans_reg_cache & ~0xC);
@@ -1024,6 +1028,7 @@ static int __devinit tps80031_regulator_probe(struct platform_device *pdev)
ri->dev = &pdev->dev;
if (tps_pdata->delay_us > 0)
ri->delay = tps_pdata->delay_us;
+ ri->tolerance_uv = tps_pdata->tolerance_uv;
check_smps_mode_mult(pdev->dev.parent, ri);
ri->platform_flags = tps_pdata->flags;
diff --git a/drivers/rtc/rtc-max77663.c b/drivers/rtc/rtc-max77663.c
index 874a2df86dc1..13d8062e1def 100644
--- a/drivers/rtc/rtc-max77663.c
+++ b/drivers/rtc/rtc-max77663.c
@@ -2,8 +2,8 @@
* drivers/rtc/rtc-max77663.c
* Max77663 RTC driver
*
- * Copyright 2011 Maxim Integrated Products, Inc.
- * Copyright (C) 2011 NVIDIA Corporation
+ * Copyright 2011-2012, Maxim Integrated Products, Inc.
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -97,6 +97,7 @@ struct max77663_rtc {
struct mutex io_lock;
int irq;
u8 irq_mask;
+ bool shutdown_ongoing;
};
static inline struct device *_to_parent(struct max77663_rtc *rtc)
@@ -443,6 +444,11 @@ static int max77663_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
u8 buf[RTC_NR];
int ret;
+ if (rtc->shutdown_ongoing) {
+ dev_warn(rtc->dev, "rtc_set_alarm: "
+ "Device shutdown on-going, skip alarm setting.\n");
+ return -ESHUTDOWN;
+ }
dev_dbg(rtc->dev, "rtc_set_alarm: "
"tm: %d-%02d-%02d %02d:%02d:%02d, wday=%d [%s]\n",
alrm->time.tm_year, alrm->time.tm_mon, alrm->time.tm_mday,
@@ -534,7 +540,7 @@ static int max77663_rtc_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "probe: kzalloc() failed\n");
return -ENOMEM;
}
-
+ rtc->shutdown_ongoing = false;
dev_set_drvdata(&pdev->dev, rtc);
rtc->dev = &pdev->dev;
mutex_init(&rtc->io_lock);
@@ -591,6 +597,17 @@ static int __devexit max77663_rtc_remove(struct platform_device *pdev)
return 0;
}
+static void max77663_rtc_shutdown(struct platform_device *pdev)
+{
+ struct max77663_rtc *rtc = dev_get_drvdata(&pdev->dev);
+ u8 buf[RTC_NR] = { 0x0, 0x0, 0x0, 0x1, 0x1, 0x0, 0x1 };
+
+ rtc->shutdown_ongoing = true;
+ dev_info(rtc->dev, "rtc_shutdown: clean alarm\n");
+ max77663_rtc_write(rtc, MAX77663_RTC_ALARM_SEC1, buf, sizeof(buf), 1);
+ max77663_rtc_alarm_irq_enable(&pdev->dev, 0);
+}
+
static struct platform_driver max77663_rtc_driver = {
.probe = max77663_rtc_probe,
.remove = __devexit_p(max77663_rtc_remove),
@@ -598,6 +615,7 @@ static struct platform_driver max77663_rtc_driver = {
.name = "max77663-rtc",
.owner = THIS_MODULE,
},
+ .shutdown = max77663_rtc_shutdown,
};
static int __init max77663_rtc_init(void)
diff --git a/drivers/rtc/rtc-tps6591x.c b/drivers/rtc/rtc-tps6591x.c
index 6223f1108f06..ebc46b4cf46e 100644
--- a/drivers/rtc/rtc-tps6591x.c
+++ b/drivers/rtc/rtc-tps6591x.c
@@ -162,7 +162,7 @@ static int tps6591x_rtc_read_time(struct device *dev, struct rtc_time *tm)
tm->tm_hour = buff[2];
tm->tm_mday = buff[3];
tm->tm_mon = buff[4] - 1;
- tm->tm_year = buff[5];
+ tm->tm_year = buff[5] + RTC_YEAR_OFFSET;
tm->tm_wday = buff[6];
print_time(dev, tm);
return tps6591x_rtc_valid_tm(tm);
@@ -250,7 +250,7 @@ static int tps6591x_rtc_set_time(struct device *dev, struct rtc_time *tm)
buff[2] = tm->tm_hour;
buff[3] = tm->tm_mday;
buff[4] = tm->tm_mon + 1;
- buff[5] = tm->tm_year;
+ buff[5] = tm->tm_year % RTC_YEAR_OFFSET;
buff[6] = tm->tm_wday;
print_time(dev, tm);
@@ -345,7 +345,7 @@ static int tps6591x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
buff[2] = alrm->time.tm_hour;
buff[3] = alrm->time.tm_mday;
buff[4] = alrm->time.tm_mon + 1;
- buff[5] = alrm->time.tm_year;
+ buff[5] = alrm->time.tm_year % RTC_YEAR_OFFSET;
convert_decimal_to_bcd(buff, sizeof(buff));
err = tps6591x_write_regs(dev, RTC_ALARM, sizeof(buff), buff);
if (err)
@@ -369,7 +369,7 @@ static int tps6591x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
alrm->time.tm_hour = buff[2];
alrm->time.tm_mday = buff[3];
alrm->time.tm_mon = buff[4] - 1;
- alrm->time.tm_year = buff[5];
+ alrm->time.tm_year = buff[5] + RTC_YEAR_OFFSET;
dev_info(dev->parent, "\n getting alarm time::\n");
print_time(dev, &alrm->time);
diff --git a/drivers/rtc/rtc-tps80031.c b/drivers/rtc/rtc-tps80031.c
index 70d6734a5708..b2b9d04171c5 100644
--- a/drivers/rtc/rtc-tps80031.c
+++ b/drivers/rtc/rtc-tps80031.c
@@ -31,6 +31,7 @@
#include <linux/platform_device.h>
#include <linux/rtc.h>
#include <linux/slab.h>
+#include <linux/gpio.h>
#define RTC_CTRL 0x10
#define RTC_STATUS 0x11
@@ -65,8 +66,25 @@ struct tps80031_rtc {
int irq;
struct rtc_device *rtc;
u8 alarm_irq_enabled;
+ int msecure_gpio;
};
+static inline void tps80031_enable_rtc_write(struct device *dev)
+{
+ struct tps80031_rtc *rtc = dev_get_drvdata(dev);
+
+ if (rtc->msecure_gpio >= 0)
+ gpio_set_value(rtc->msecure_gpio, 1);
+}
+
+static inline void tps80031_disable_rtc_write(struct device *dev)
+{
+ struct tps80031_rtc *rtc = dev_get_drvdata(dev);
+
+ if (rtc->msecure_gpio >= 0)
+ gpio_set_value(rtc->msecure_gpio, 0);
+}
+
static int tps80031_read_regs(struct device *dev, int reg, int len,
uint8_t *val)
{
@@ -93,13 +111,16 @@ static int tps80031_write_regs(struct device *dev, int reg, int len,
uint8_t *val)
{
int ret;
+
+ tps80031_enable_rtc_write(dev);
ret = tps80031_writes(dev->parent, 1, reg, len, val);
if (ret < 0) {
+ tps80031_disable_rtc_write(dev);
dev_err(dev->parent, "failed writing reg: %d\n", reg);
WARN_ON(1);
return ret;
}
-
+ tps80031_disable_rtc_write(dev);
return 0;
}
@@ -150,18 +171,24 @@ static int tps80031_rtc_read_time(struct device *dev, struct rtc_time *tm)
static int tps80031_rtc_stop(struct device *dev)
{
int err;
+
+ tps80031_enable_rtc_write(dev);
err = tps80031_clr_bits(dev->parent, 1, RTC_CTRL, STOP_RTC);
if (err < 0)
dev_err(dev->parent, "failed to stop RTC. err: %d\n", err);
+ tps80031_disable_rtc_write(dev);
return err;
}
static int tps80031_rtc_start(struct device *dev)
{
int err;
+
+ tps80031_enable_rtc_write(dev);
err = tps80031_set_bits(dev->parent, 1, RTC_CTRL, STOP_RTC);
if (err < 0)
dev_err(dev->parent, "failed to start RTC. err: %d\n", err);
+ tps80031_disable_rtc_write(dev);
return err;
}
@@ -262,7 +289,9 @@ static int tps80031_rtc_alarm_irq_enable(struct device *dev,
if (rtc->alarm_irq_enabled)
return 0;
+ tps80031_enable_rtc_write(dev);
err = tps80031_set_bits(p, 1, RTC_INT, ENABLE_ALARM_INT);
+ tps80031_disable_rtc_write(dev);
if (err < 0) {
dev_err(p, "failed to set ALRM int. err: %d\n", err);
return err;
@@ -271,7 +300,9 @@ static int tps80031_rtc_alarm_irq_enable(struct device *dev,
} else {
if(!rtc->alarm_irq_enabled)
return 0;
+ tps80031_enable_rtc_write(dev);
err = tps80031_clr_bits(p, 1, RTC_INT, ENABLE_ALARM_INT);
+ tps80031_disable_rtc_write(dev);
if (err < 0) {
dev_err(p, "failed to clear ALRM int. err: %d\n", err);
return err;
@@ -303,8 +334,10 @@ static irqreturn_t tps80031_rtc_irq(int irq, void *data)
return -EBUSY;
}
+ tps80031_enable_rtc_write(dev);
err = tps80031_force_update(dev->parent, 1, RTC_STATUS,
ALARM_INT_STATUS, ALARM_INT_STATUS);
+ tps80031_disable_rtc_write(dev);
if (err) {
dev_err(dev->parent, "unable to set Alarm INT\n");
return -EBUSY;
@@ -335,8 +368,19 @@ static int __devinit tps80031_rtc_probe(struct platform_device *pdev)
if (pdata->irq < 0)
dev_err(&pdev->dev, "no IRQ specified, wakeup is disabled\n");
+ rtc->msecure_gpio = -1;
+ if (gpio_is_valid(pdata->msecure_gpio)) {
+ err = gpio_request(pdata->msecure_gpio, "tps80031 msecure");
+ if (err == 0) {
+ rtc->msecure_gpio = pdata->msecure_gpio;
+ gpio_direction_output(rtc->msecure_gpio, 0);
+ } else
+ dev_warn(&pdev->dev, "could not get msecure GPIO\n");
+ }
+
rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,
&tps80031_rtc_ops, THIS_MODULE);
+ dev_set_drvdata(&pdev->dev, rtc);
if (IS_ERR(rtc->rtc)) {
err = PTR_ERR(rtc->rtc);
@@ -379,7 +423,9 @@ static int __devinit tps80031_rtc_probe(struct platform_device *pdev)
return -EBUSY;
}
+ tps80031_enable_rtc_write(&pdev->dev);
err = tps80031_set_bits(pdev->dev.parent, 1, RTC_INT, ENABLE_ALARM_INT);
+ tps80031_disable_rtc_write(&pdev->dev);
if (err) {
dev_err(&pdev->dev, "unable to program Interrupt Mask reg\n");
err = -EBUSY;
@@ -388,7 +434,6 @@ static int __devinit tps80031_rtc_probe(struct platform_device *pdev)
} else
rtc->alarm_irq_enabled = 1;
- dev_set_drvdata(&pdev->dev, rtc);
if (pdata && (pdata->irq >= 0)) {
rtc->irq = pdata->irq;
err = request_threaded_irq(pdata->irq, NULL, tps80031_rtc_irq,
diff --git a/drivers/spi/spi-tegra.c b/drivers/spi/spi-tegra.c
index 3f913389dd7c..cf1b7bf40c62 100644
--- a/drivers/spi/spi-tegra.c
+++ b/drivers/spi/spi-tegra.c
@@ -42,6 +42,8 @@
#include <mach/dma.h>
#include <mach/clk.h>
+#define SPI_PM_RUNTIME_ENABLE 0
+
#define SLINK_COMMAND 0x000
#define SLINK_BIT_LENGTH(x) (((x) & 0x1f) << 0)
#define SLINK_WORD_SIZE(x) (((x) & 0x1f) << 5)
@@ -144,7 +146,6 @@
#define DATA_DIR_TX (1 << 0)
#define DATA_DIR_RX (1 << 1)
-#define SPI_FIFO_DEPTH 32
#define SLINK_DMA_TIMEOUT (msecs_to_jiffies(1000))
@@ -169,12 +170,13 @@ static const unsigned long spi_tegra_req_sels[] = {
RX_FIFO_FULL_COUNT_ZERO << 16)
#define MAX_CHIP_SELECT 4
-#define SLINK_FIFO_DEPTH 4
+#define SLINK_FIFO_DEPTH 32
struct spi_tegra_data {
struct spi_master *master;
struct platform_device *pdev;
spinlock_t lock;
+ spinlock_t reg_lock;
char port_name[32];
struct clk *clk;
@@ -215,7 +217,7 @@ struct spi_tegra_data {
bool is_curr_dma_xfer;
bool is_clkon_always;
- bool clk_state;
+ int clk_state;
bool is_suspended;
bool is_hw_based_cs;
@@ -247,22 +249,81 @@ struct spi_tegra_data {
struct work_struct spi_transfer_work;
};
+static int tegra_spi_runtime_idle(struct device *dev);
+static int tegra_spi_runtime_resume(struct device *dev);
+
static inline unsigned long spi_tegra_readl(struct spi_tegra_data *tspi,
unsigned long reg)
{
- if (!tspi->clk_state)
+ unsigned long flags;
+ unsigned long val;
+
+ spin_lock_irqsave(&tspi->reg_lock, flags);
+ if (tspi->clk_state < 1)
BUG();
- return readl(tspi->base + reg);
+ val = readl(tspi->base + reg);
+ spin_unlock_irqrestore(&tspi->reg_lock, flags);
+ return val;
}
static inline void spi_tegra_writel(struct spi_tegra_data *tspi,
unsigned long val, unsigned long reg)
{
- if (!tspi->clk_state)
+ unsigned long flags;
+
+ spin_lock_irqsave(&tspi->reg_lock, flags);
+ if (tspi->clk_state < 1)
BUG();
writel(val, tspi->base + reg);
+
+ /* Synchronize write by reading back the register */
+ readl(tspi->base + SLINK_MAS_DATA);
+ spin_unlock_irqrestore(&tspi->reg_lock, flags);
}
+static int tegra_spi_clk_disable(struct spi_tegra_data *tspi)
+{
+ unsigned long flags;
+
+ /* Flush all write which are in PPSB queue by reading back */
+ spi_tegra_readl(tspi, SLINK_MAS_DATA);
+
+ spin_lock_irqsave(&tspi->reg_lock, flags);
+ tspi->clk_state--;
+ spin_unlock_irqrestore(&tspi->reg_lock, flags);
+ clk_disable(tspi->clk);
+ clk_disable(tspi->sclk);
+ return 0;
+}
+
+static int tegra_spi_clk_enable(struct spi_tegra_data *tspi)
+{
+ unsigned long flags;
+
+ clk_enable(tspi->sclk);
+ clk_enable(tspi->clk);
+ spin_lock_irqsave(&tspi->reg_lock, flags);
+ tspi->clk_state++;
+ spin_unlock_irqrestore(&tspi->reg_lock, flags);
+ return 0;
+}
+
+#if SPI_PM_RUNTIME_ENABLE
+#define spi_pm_runtime_get_sync(dev) pm_runtime_get_sync(dev)
+#define spi_pm_runtime_put_sync(dev) pm_runtime_put_sync(dev)
+#define spi_pm_runtime_enable(dev) pm_runtime_enable(dev)
+#define spi_pm_runtime_disable(dev) pm_runtime_disable(dev)
+#define spi_pm_runtime_enabled(dev) pm_runtime_enabled(dev)
+#define spi_pm_runtime_status_suspended(dev) pm_runtime_status_suspended(dev)
+#else
+#define spi_pm_runtime_get_sync(dev) tegra_spi_runtime_resume(dev)
+#define spi_pm_runtime_put_sync(dev) tegra_spi_runtime_idle(dev)
+#define spi_pm_runtime_enable(dev) do { } while(0)
+#define spi_pm_runtime_disable(dev) do { } while(0)
+#define spi_pm_runtime_enabled(dev) true
+#define spi_pm_runtime_status_suspended(dev) true
+#endif
+
static void cancel_dma(struct tegra_dma_channel *dma_chan,
struct tegra_dma_req *req)
{
@@ -341,12 +402,12 @@ static unsigned spi_tegra_calculate_curr_xfer_param(
if (tspi->is_packed) {
max_len = min(remain_len, tspi->max_buf_size);
tspi->curr_dma_words = max_len/tspi->bytes_per_word;
- total_fifo_words = remain_len/4;
+ total_fifo_words = max_len/4;
} else {
max_word = (remain_len - 1) / tspi->bytes_per_word + 1;
max_word = min(max_word, tspi->max_buf_size/4);
tspi->curr_dma_words = max_word;
- total_fifo_words = remain_len/tspi->bytes_per_word;
+ total_fifo_words = max_word;
}
return total_fifo_words;
}
@@ -441,7 +502,8 @@ static void spi_tegra_copy_client_txbuf_to_spi_txbuf(
/* Make the dma buffer to read by cpu */
dma_sync_single_for_cpu(&tspi->pdev->dev, tspi->tx_buf_phys,
- tspi->dma_buf_size, DMA_FROM_DEVICE);
+ tspi->dma_buf_size, DMA_TO_DEVICE);
+
if (tspi->is_packed) {
len = tspi->curr_dma_words * tspi->bytes_per_word;
memcpy(tspi->tx_buf, t->tx_buf + tspi->cur_pos, len);
@@ -461,6 +523,7 @@ static void spi_tegra_copy_client_txbuf_to_spi_txbuf(
}
}
tspi->cur_tx_pos += tspi->curr_dma_words * tspi->bytes_per_word;
+
/* Make the dma buffer to read by dma */
dma_sync_single_for_device(&tspi->pdev->dev, tspi->tx_buf_phys,
tspi->dma_buf_size, DMA_TO_DEVICE);
@@ -499,7 +562,7 @@ static void spi_tegra_copy_spi_rxbuf_to_client_rxbuf(
/* Make the dma buffer to read by dma */
dma_sync_single_for_device(&tspi->pdev->dev, tspi->rx_buf_phys,
- tspi->dma_buf_size, DMA_TO_DEVICE);
+ tspi->dma_buf_size, DMA_FROM_DEVICE);
}
static int spi_tegra_start_dma_based_transfer(
@@ -547,9 +610,6 @@ static int spi_tegra_start_dma_based_transfer(
if (tspi->cur_direction & DATA_DIR_TX) {
spi_tegra_copy_client_txbuf_to_spi_txbuf(tspi, t);
wmb();
- /* Make the dma buffer to read by dma */
- dma_sync_single_for_device(&tspi->pdev->dev, tspi->tx_buf_phys,
- tspi->dma_buf_size, DMA_TO_DEVICE);
tspi->tx_dma_req.size = len;
ret = tegra_dma_enqueue_req(tspi->tx_dma, &tspi->tx_dma_req);
if (ret < 0) {
@@ -567,7 +627,8 @@ static int spi_tegra_start_dma_based_transfer(
if (tspi->cur_direction & DATA_DIR_RX) {
/* Make the dma buffer to read by dma */
dma_sync_single_for_device(&tspi->pdev->dev, tspi->rx_buf_phys,
- tspi->dma_buf_size, DMA_TO_DEVICE);
+ tspi->dma_buf_size, DMA_FROM_DEVICE);
+
tspi->rx_dma_req.size = len;
ret = tegra_dma_enqueue_req(tspi->rx_dma, &tspi->rx_dma_req);
if (ret < 0) {
@@ -585,6 +646,7 @@ static int spi_tegra_start_dma_based_transfer(
udelay(1);
wmb();
}
+ tspi->dma_control_reg = val;
val |= SLINK_DMA_EN;
spi_tegra_writel(tspi, val, SLINK_DMA_CTL);
@@ -622,6 +684,7 @@ static int spi_tegra_start_cpu_based_transfer(
udelay(1);
wmb();
}
+ tspi->dma_control_reg = val;
val |= SLINK_DMA_EN;
spi_tegra_writel(tspi, val, SLINK_DMA_CTL);
return 0;
@@ -731,11 +794,11 @@ static void spi_tegra_start_transfer(struct spi_device *spi,
command2 = tspi->def_command2_reg;
if (is_first_of_msg) {
- if (!tspi->is_clkon_always) {
- if (!tspi->clk_state) {
- pm_runtime_get_sync(&tspi->pdev->dev);
- tspi->clk_state = 1;
- }
+ if ((ret = spi_pm_runtime_get_sync(&tspi->pdev->dev)) < 0) {
+ dev_err(&tspi->pdev->dev,
+ "%s: spi_pm_runtime_get_sync() returns %d\n",
+ __func__, ret);
+ return;
}
spi_tegra_clear_status(tspi);
@@ -806,7 +869,7 @@ static void spi_tegra_start_transfer(struct spi_device *spi,
spi_tegra_writel(tspi, command2, SLINK_COMMAND2);
tspi->command2_reg = command2;
- if (total_fifo_words > SPI_FIFO_DEPTH)
+ if (total_fifo_words > SLINK_FIFO_DEPTH)
ret = spi_tegra_start_dma_based_transfer(tspi, t);
else
ret = spi_tegra_start_cpu_based_transfer(tspi, t);
@@ -848,6 +911,8 @@ static int spi_tegra_setup(struct spi_device *spi)
return -EINVAL;
}
+ spi_pm_runtime_get_sync(&tspi->pdev->dev);
+
spin_lock_irqsave(&tspi->lock, flags);
val = tspi->def_command_reg;
if (spi->mode & SPI_CS_HIGH)
@@ -855,20 +920,10 @@ static int spi_tegra_setup(struct spi_device *spi)
else
val &= ~cs_bit;
tspi->def_command_reg = val;
-
- if (!tspi->is_clkon_always && !tspi->clk_state) {
- spin_unlock_irqrestore(&tspi->lock, flags);
- pm_runtime_get_sync(&tspi->pdev->dev);
- spin_lock_irqsave(&tspi->lock, flags);
- tspi->clk_state = 1;
- }
spi_tegra_writel(tspi, tspi->def_command_reg, SLINK_COMMAND);
- if (!tspi->is_clkon_always && tspi->clk_state) {
- tspi->clk_state = 0;
- spin_unlock_irqrestore(&tspi->lock, flags);
- pm_runtime_put_sync(&tspi->pdev->dev);
- } else
- spin_unlock_irqrestore(&tspi->lock, flags);
+ spin_unlock_irqrestore(&tspi->lock, flags);
+
+ spi_pm_runtime_put_sync(&tspi->pdev->dev);
return 0;
}
@@ -968,6 +1023,11 @@ static void spi_tegra_curr_transfer_complete(struct spi_tegra_data *tspi,
udelay(tspi->cur->delay_usecs);
}
+ if (list_empty(&tspi->queue)) {
+ dev_err(&tspi->pdev->dev, "Handling empty list\n");
+ return;
+ }
+
m = list_first_entry(&tspi->queue, struct spi_message, queue);
if (err)
m->status = -EIO;
@@ -1010,19 +1070,11 @@ static void spi_tegra_curr_transfer_complete(struct spi_tegra_data *tspi,
SLINK_COMMAND);
spi_tegra_writel(tspi, tspi->def_command2_reg,
SLINK_COMMAND2);
- if (!tspi->is_clkon_always) {
- if (tspi->clk_state) {
- /* Provide delay to stablize the signal
- state */
- spin_unlock_irqrestore(&tspi->lock,
- *irq_flags);
- udelay(10);
- pm_runtime_put_sync(&tspi->pdev->dev);
- spin_lock_irqsave(&tspi->lock,
- *irq_flags);
- tspi->clk_state = 0;
- }
- }
+ /* Provide delay to stablize the signal state */
+ spin_unlock_irqrestore(&tspi->lock, *irq_flags);
+ udelay(10);
+ spi_pm_runtime_put_sync(&tspi->pdev->dev);
+ spin_lock_irqsave(&tspi->lock, *irq_flags);
tspi->is_transfer_in_progress = false;
/* Check if any new request has come between
* clock disable */
@@ -1056,6 +1108,9 @@ static void handle_cpu_based_xfer(void *context_data)
(tspi->status_reg & SLINK_BSY)) {
dev_err(&tspi->pdev->dev, "%s ERROR bit set 0x%x\n",
__func__, tspi->status_reg);
+ dev_err(&tspi->pdev->dev, "%s 0x%08x:0x%08x:0x%08x\n",
+ __func__, tspi->command_reg, tspi->command2_reg,
+ tspi->dma_control_reg);
tegra_periph_reset_assert(tspi->clk);
udelay(2);
tegra_periph_reset_deassert(tspi->clk);
@@ -1144,6 +1199,9 @@ static irqreturn_t spi_tegra_isr_thread(int irq, void *context_data)
if (err) {
dev_err(&tspi->pdev->dev, "%s ERROR bit set 0x%x\n",
__func__, tspi->status_reg);
+ dev_err(&tspi->pdev->dev, "%s 0x%08x:0x%08x:0x%08x\n",
+ __func__, tspi->command_reg, tspi->command2_reg,
+ tspi->dma_control_reg);
tegra_periph_reset_assert(tspi->clk);
udelay(2);
tegra_periph_reset_deassert(tspi->clk);
@@ -1173,7 +1231,7 @@ static irqreturn_t spi_tegra_isr_thread(int irq, void *context_data)
/* Continue transfer in current message */
total_fifo_words = spi_tegra_calculate_curr_xfer_param(tspi->cur_spi,
tspi, t);
- if (total_fifo_words > SPI_FIFO_DEPTH)
+ if (total_fifo_words > SLINK_FIFO_DEPTH)
err = spi_tegra_start_dma_based_transfer(tspi, t);
else
err = spi_tegra_start_cpu_based_transfer(tspi, t);
@@ -1201,6 +1259,87 @@ static irqreturn_t spi_tegra_isr(int irq, void *context_data)
return IRQ_WAKE_THREAD;
}
+static void spi_tegra_deinit_dma_param(struct spi_tegra_data *tspi,
+ bool dma_to_memory)
+{
+ struct tegra_dma_channel *tdc;
+ u32 *dma_buf;
+ dma_addr_t dma_phys;
+
+ if (dma_to_memory) {
+ dma_buf = tspi->rx_buf;
+ tdc = tspi->rx_dma;
+ dma_phys = tspi->rx_buf_phys;
+ tspi->rx_dma = NULL;
+ tspi->rx_buf = NULL;
+ } else {
+ dma_buf = tspi->tx_buf;
+ tdc = tspi->tx_dma;
+ dma_phys = tspi->tx_buf_phys;
+ tspi->tx_buf = NULL;
+ tspi->tx_dma = NULL;
+ }
+
+ dma_free_coherent(&tspi->pdev->dev, tspi->dma_buf_size,
+ dma_buf, dma_phys);
+ tegra_dma_free_channel(tdc);
+}
+
+static int __init spi_tegra_init_dma_param(struct spi_tegra_data *tspi,
+ bool dma_to_memory)
+{
+ struct tegra_dma_req *dma_req;
+ struct tegra_dma_channel *tdc;
+ u32 *dma_buf;
+ dma_addr_t dma_phys;
+
+ tdc = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT, "spi_%s_%d",
+ (dma_to_memory) ? "rx" : "tx", tspi->pdev->id);
+ if (!tdc) {
+ dev_err(&tspi->pdev->dev, "can not allocate rx dma channel\n");
+ return -ENODEV;
+ }
+
+ dma_buf = dma_alloc_coherent(&tspi->pdev->dev, tspi->dma_buf_size,
+ &dma_phys, GFP_KERNEL);
+ if (!dma_buf) {
+ dev_err(&tspi->pdev->dev, "can not allocate rx bounce buffer");
+ tegra_dma_free_channel(tdc);
+ return -ENOMEM;
+ }
+
+ dma_req = (dma_to_memory) ? &tspi->rx_dma_req : &tspi->tx_dma_req;
+ memset(dma_req, 0, sizeof(*dma_req));
+
+ dma_req->req_sel = spi_tegra_req_sels[tspi->pdev->id];
+ dma_req->dev = tspi;
+ dma_req->dest_bus_width = 32;
+ dma_req->source_bus_width = 32;
+ dma_req->to_memory = (dma_to_memory) ? 1 : 0;
+ dma_req->virt_addr = dma_buf;
+ dma_req->dest_wrap = 0;
+ dma_req->source_wrap = 0;
+
+ if (dma_to_memory) {
+ dma_req->complete = tegra_spi_rx_dma_complete;
+ dma_req->dest_addr = dma_phys;
+ dma_req->source_addr = tspi->phys + SLINK_RX_FIFO;
+ dma_req->source_wrap = 4;
+ tspi->rx_buf_phys = dma_phys;
+ tspi->rx_buf = dma_buf;
+ tspi->rx_dma = tdc;
+ } else {
+ dma_req->complete = tegra_spi_tx_dma_complete;
+ dma_req->dest_addr = tspi->phys + SLINK_TX_FIFO;
+ dma_req->source_addr = dma_phys;
+ dma_req->dest_wrap = 4;
+ tspi->tx_buf = dma_buf;
+ tspi->tx_buf_phys = dma_phys;
+ tspi->tx_dma = tdc;
+ }
+ return 0;
+}
+
static int __init spi_tegra_probe(struct platform_device *pdev)
{
struct spi_master *master;
@@ -1234,57 +1373,53 @@ static int __init spi_tegra_probe(struct platform_device *pdev)
tspi->is_transfer_in_progress = false;
tspi->is_suspended = false;
spin_lock_init(&tspi->lock);
+ spin_lock_init(&tspi->reg_lock);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (r == NULL) {
+ if (!r) {
+ dev_err(&pdev->dev, "No IO memory resource\n");
ret = -ENODEV;
- goto fail_no_mem;
- }
-
- if (!request_mem_region(r->start, resource_size(r),
- dev_name(&pdev->dev))) {
- ret = -EBUSY;
- goto fail_no_mem;
+ goto exit_free_master;
}
-
tspi->phys = r->start;
- tspi->base = ioremap(r->start, resource_size(r));
+ tspi->base = devm_request_and_ioremap(&pdev->dev, r);
if (!tspi->base) {
- dev_err(&pdev->dev, "can't ioremap iomem\n");
- ret = -ENOMEM;
- goto fail_io_map;
+ dev_err(&pdev->dev,
+ "Cannot request memregion/iomap dma address\n");
+ ret = -EADDRNOTAVAIL;
+ goto exit_free_master;
}
spi_irq = platform_get_irq(pdev, 0);
if (unlikely(spi_irq < 0)) {
dev_err(&pdev->dev, "can't find irq resource\n");
ret = -ENXIO;
- goto fail_irq_req;
+ goto exit_free_master;
}
tspi->irq = spi_irq;
sprintf(tspi->port_name, "tegra_spi_%d", pdev->id);
- ret = request_threaded_irq(tspi->irq, spi_tegra_isr,
- spi_tegra_isr_thread, IRQF_DISABLED,
+ ret = devm_request_threaded_irq(&pdev->dev, tspi->irq,
+ spi_tegra_isr, spi_tegra_isr_thread, IRQF_ONESHOT,
tspi->port_name, tspi);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register ISR for IRQ %d\n",
tspi->irq);
- goto fail_irq_req;
+ goto exit_free_master;
}
- tspi->clk = clk_get(&pdev->dev, "spi");
+ tspi->clk = devm_clk_get(&pdev->dev, "spi");
if (IS_ERR(tspi->clk)) {
dev_err(&pdev->dev, "can not get clock\n");
ret = PTR_ERR(tspi->clk);
- goto fail_clk_get;
+ goto exit_free_master;
}
- tspi->sclk = clk_get(&pdev->dev, "sclk");
+ tspi->sclk = devm_clk_get(&pdev->dev, "sclk");
if (IS_ERR(tspi->sclk)) {
dev_err(&pdev->dev, "can not get sclock\n");
ret = PTR_ERR(tspi->sclk);
- goto fail_sclk_get;
+ goto exit_free_master;
}
INIT_LIST_HEAD(&tspi->queue);
@@ -1327,92 +1462,41 @@ static int __init spi_tegra_probe(struct platform_device *pdev)
init_completion(&tspi->tx_dma_complete);
init_completion(&tspi->rx_dma_complete);
-
- tspi->rx_dma = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT,
- "spi_rx_%d", pdev->id);
- if (!tspi->rx_dma) {
- dev_err(&pdev->dev, "can not allocate rx dma channel\n");
- ret = -ENODEV;
- goto fail_rx_dma_alloc;
- }
-
- tspi->rx_buf = dma_alloc_coherent(&pdev->dev, tspi->dma_buf_size,
- &tspi->rx_buf_phys, GFP_KERNEL);
- if (!tspi->rx_buf) {
- dev_err(&pdev->dev, "can not allocate rx bounce buffer\n");
- ret = -ENOMEM;
- goto fail_rx_buf_alloc;
- }
-
- /* Make the dma buffer to read by dma */
- dma_sync_single_for_device(&tspi->pdev->dev, tspi->rx_buf_phys,
- tspi->dma_buf_size, DMA_TO_DEVICE);
-
- memset(&tspi->rx_dma_req, 0, sizeof(struct tegra_dma_req));
- tspi->rx_dma_req.complete = tegra_spi_rx_dma_complete;
- tspi->rx_dma_req.to_memory = 1;
- tspi->rx_dma_req.dest_addr = tspi->rx_buf_phys;
- tspi->rx_dma_req.virt_addr = tspi->rx_buf;
- tspi->rx_dma_req.dest_bus_width = 32;
- tspi->rx_dma_req.source_addr = tspi->phys + SLINK_RX_FIFO;
- tspi->rx_dma_req.source_bus_width = 32;
- tspi->rx_dma_req.source_wrap = 4;
- tspi->rx_dma_req.dest_wrap = 0;
- tspi->rx_dma_req.req_sel = spi_tegra_req_sels[pdev->id];
- tspi->rx_dma_req.dev = tspi;
-
- tspi->tx_dma = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT,
- "spi_tx_%d", pdev->id);
- if (!tspi->tx_dma) {
- dev_err(&pdev->dev, "can not allocate tx dma channel\n");
- ret = -ENODEV;
- goto fail_tx_dma_alloc;
+ ret = spi_tegra_init_dma_param(tspi, true);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Error in rx dma init\n");
+ goto exit_free_master;
}
- tspi->tx_buf = dma_alloc_coherent(&pdev->dev, tspi->dma_buf_size,
- &tspi->tx_buf_phys, GFP_KERNEL);
- if (!tspi->tx_buf) {
- dev_err(&pdev->dev, "can not allocate tx bounce buffer\n");
- ret = -ENOMEM;
- goto fail_tx_buf_alloc;
+ ret = spi_tegra_init_dma_param(tspi, false);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Error in tx dma init\n");
+ goto exit_rx_dma_free;
}
- /* Make the dma buffer to read by dma */
- dma_sync_single_for_device(&tspi->pdev->dev, tspi->tx_buf_phys,
- tspi->dma_buf_size, DMA_TO_DEVICE);
-
- memset(&tspi->tx_dma_req, 0, sizeof(struct tegra_dma_req));
- tspi->tx_dma_req.complete = tegra_spi_tx_dma_complete;
- tspi->tx_dma_req.to_memory = 0;
- tspi->tx_dma_req.dest_addr = tspi->phys + SLINK_TX_FIFO;
- tspi->tx_dma_req.virt_addr = tspi->tx_buf;
- tspi->tx_dma_req.dest_bus_width = 32;
- tspi->tx_dma_req.dest_wrap = 4;
- tspi->tx_dma_req.source_wrap = 0;
- tspi->tx_dma_req.source_addr = tspi->tx_buf_phys;
- tspi->tx_dma_req.source_bus_width = 32;
- tspi->tx_dma_req.req_sel = spi_tegra_req_sels[pdev->id];
- tspi->tx_dma_req.dev = tspi;
tspi->max_buf_size = tspi->dma_buf_size;
tspi->def_command_reg = SLINK_CS_SW | SLINK_M_S;
tspi->def_command2_reg = SLINK_CS_ACTIVE_BETWEEN;
skip_dma_alloc:
- pm_runtime_enable(&pdev->dev);
- pm_runtime_get_sync(&pdev->dev);
- tspi->clk_state = 1;
- master->dev.of_node = pdev->dev.of_node;
- ret = spi_register_master(master);
- if (!tspi->is_clkon_always) {
- if (tspi->clk_state) {
- pm_runtime_put_sync(&pdev->dev);
- tspi->clk_state = 0;
+ spi_pm_runtime_enable(&pdev->dev);
+ if (!spi_pm_runtime_enabled(&pdev->dev)) {
+ ret = tegra_spi_runtime_resume(&pdev->dev);
+ if (ret) {
+ dev_err(&pdev->dev, "runtime resume failed %d", ret);
+ goto exit_pm_disable;
}
}
+ /* Enable clock if it is require to be enable always */
+ if (tspi->is_clkon_always)
+ spi_pm_runtime_get_sync(&pdev->dev);
+
+ master->dev.of_node = pdev->dev.of_node;
+ ret = spi_register_master(master);
if (ret < 0) {
dev_err(&pdev->dev, "can not register to master err %d\n", ret);
- goto fail_master_register;
+ goto exit_pm_suspend;
}
/* create the workqueue for the kbc path */
@@ -1421,42 +1505,32 @@ skip_dma_alloc:
if (!tspi->spi_workqueue) {
dev_err(&pdev->dev, "Failed to create work queue\n");
ret = -ENODEV;
- goto fail_workqueue;
+ goto exit_master_unregister;
}
INIT_WORK(&tspi->spi_transfer_work, tegra_spi_transfer_work);
return ret;
-fail_workqueue:
+exit_master_unregister:
spi_unregister_master(master);
-fail_master_register:
- if (tspi->tx_buf)
- dma_free_coherent(&pdev->dev, tspi->dma_buf_size,
- tspi->tx_buf, tspi->tx_buf_phys);
-fail_tx_buf_alloc:
- if (tspi->tx_dma)
- tegra_dma_free_channel(tspi->tx_dma);
-fail_tx_dma_alloc:
- if (tspi->rx_buf)
- dma_free_coherent(&pdev->dev, tspi->dma_buf_size,
- tspi->rx_buf, tspi->rx_buf_phys);
-fail_rx_buf_alloc:
- if (tspi->rx_dma)
- tegra_dma_free_channel(tspi->rx_dma);
-fail_rx_dma_alloc:
- pm_runtime_disable(&pdev->dev);
- clk_put(tspi->sclk);
-fail_sclk_get:
- clk_put(tspi->clk);
-fail_clk_get:
- free_irq(tspi->irq, tspi);
-fail_irq_req:
- iounmap(tspi->base);
-fail_io_map:
- release_mem_region(r->start, resource_size(r));
-fail_no_mem:
+ if (tspi->is_clkon_always)
+ spi_pm_runtime_put_sync(&pdev->dev);
+
+exit_pm_suspend:
+ if (!spi_pm_runtime_status_suspended(&pdev->dev))
+ tegra_spi_runtime_idle(&pdev->dev);
+
+exit_pm_disable:
+ spi_pm_runtime_disable(&pdev->dev);
+
+ spi_tegra_deinit_dma_param(tspi, false);
+
+exit_rx_dma_free:
+ spi_tegra_deinit_dma_param(tspi, true);
+
+exit_free_master:
spi_master_put(master);
return ret;
}
@@ -1465,56 +1539,44 @@ static int __devexit spi_tegra_remove(struct platform_device *pdev)
{
struct spi_master *master;
struct spi_tegra_data *tspi;
- struct resource *r;
master = dev_get_drvdata(&pdev->dev);
tspi = spi_master_get_devdata(master);
spi_unregister_master(master);
- if (tspi->tx_buf)
- dma_free_coherent(&pdev->dev, tspi->dma_buf_size,
- tspi->tx_buf, tspi->tx_buf_phys);
+
if (tspi->tx_dma)
- tegra_dma_free_channel(tspi->tx_dma);
- if (tspi->rx_buf)
- dma_free_coherent(&pdev->dev, tspi->dma_buf_size,
- tspi->rx_buf, tspi->rx_buf_phys);
+ spi_tegra_deinit_dma_param(tspi, false);
+
if (tspi->rx_dma)
- tegra_dma_free_channel(tspi->rx_dma);
+ spi_tegra_deinit_dma_param(tspi, true);
- if (tspi->is_clkon_always) {
- pm_runtime_put_sync(&pdev->dev);
- tspi->clk_state = 0;
- }
+ /* Disable clock if it is always enabled */
+ if (tspi->is_clkon_always)
+ spi_pm_runtime_put_sync(&pdev->dev);
- pm_runtime_disable(&pdev->dev);
- clk_put(tspi->sclk);
- clk_put(tspi->clk);
- iounmap(tspi->base);
+ spi_pm_runtime_disable(&pdev->dev);
+ if (!spi_pm_runtime_status_suspended(&pdev->dev))
+ tegra_spi_runtime_idle(&pdev->dev);
destroy_workqueue(tspi->spi_workqueue);
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(r->start, resource_size(r));
-
return 0;
}
#ifdef CONFIG_PM
-static int spi_tegra_suspend(struct platform_device *pdev, pm_message_t state)
+static int spi_tegra_suspend(struct device *dev)
{
- struct spi_master *master;
- struct spi_tegra_data *tspi;
- unsigned limit = 50;
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct spi_tegra_data *tspi = spi_master_get_devdata(master);
+ unsigned limit = 50;
unsigned long flags;
- master = dev_get_drvdata(&pdev->dev);
- tspi = spi_master_get_devdata(master);
spin_lock_irqsave(&tspi->lock, flags);
/* Wait for all transfer completes */
if (!list_empty(&tspi->queue))
- dev_warn(&pdev->dev, "The transfer list is not empty "
+ dev_warn(dev, "The transfer list is not empty "
"Waiting for time %d ms to complete transfer\n",
limit * 20);
@@ -1528,7 +1590,7 @@ static int spi_tegra_suspend(struct platform_device *pdev, pm_message_t state)
tspi->is_suspended = true;
if (!list_empty(&tspi->queue)) {
limit = 50;
- dev_err(&pdev->dev, "All transfer has not completed, "
+ dev_err(dev, "All transfer has not completed, "
"Waiting for %d ms current transfer to complete\n",
limit * 20);
while (tspi->is_transfer_in_progress && limit--) {
@@ -1539,7 +1601,7 @@ static int spi_tegra_suspend(struct platform_device *pdev, pm_message_t state)
}
if (tspi->is_transfer_in_progress) {
- dev_err(&pdev->dev,
+ dev_err(dev,
"Spi transfer is in progress Avoiding suspend\n");
tspi->is_suspended = false;
spin_unlock_irqrestore(&tspi->lock, flags);
@@ -1547,33 +1609,32 @@ static int spi_tegra_suspend(struct platform_device *pdev, pm_message_t state)
}
spin_unlock_irqrestore(&tspi->lock, flags);
- if (tspi->is_clkon_always) {
- pm_runtime_put_sync(&pdev->dev);
- tspi->clk_state = 0;
- }
+
+ /* Disable clock if it is always enabled */
+ if (tspi->is_clkon_always)
+ spi_pm_runtime_put_sync(dev);
+
return 0;
}
-static int spi_tegra_resume(struct platform_device *pdev)
+static int spi_tegra_resume(struct device *dev)
{
- struct spi_master *master;
- struct spi_tegra_data *tspi;
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct spi_tegra_data *tspi = spi_master_get_devdata(master);
struct spi_message *m;
struct spi_device *spi;
struct spi_transfer *t = NULL;
int single_xfer = 0;
unsigned long flags;
- master = dev_get_drvdata(&pdev->dev);
- tspi = spi_master_get_devdata(master);
+ /* Enable clock if it is always enabled */
+ if (tspi->is_clkon_always)
+ spi_pm_runtime_get_sync(dev);
- pm_runtime_get_sync(&pdev->dev);
- tspi->clk_state = 1;
+ spi_pm_runtime_get_sync(dev);
spi_tegra_writel(tspi, tspi->command_reg, SLINK_COMMAND);
- if (!tspi->is_clkon_always) {
- pm_runtime_put_sync(&pdev->dev);
- tspi->clk_state = 0;
- }
+ spi_pm_runtime_put_sync(dev);
+
spin_lock_irqsave(&tspi->lock, flags);
tspi->cur_speed = 0;
@@ -1595,38 +1656,32 @@ static int spi_tegra_resume(struct platform_device *pdev)
}
#endif
-#if defined(CONFIG_PM_RUNTIME)
-
static int tegra_spi_runtime_idle(struct device *dev)
{
- struct spi_master *master;
- struct spi_tegra_data *tspi;
- master = dev_get_drvdata(dev);
- tspi = spi_master_get_devdata(master);
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct spi_tegra_data *tspi = spi_master_get_devdata(master);
- clk_disable(tspi->clk);
- clk_disable(tspi->sclk);
- return 0;
+ return tegra_spi_clk_disable(tspi);
}
static int tegra_spi_runtime_resume(struct device *dev)
{
- struct spi_master *master;
- struct spi_tegra_data *tspi;
- master = dev_get_drvdata(dev);
- tspi = spi_master_get_devdata(master);
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct spi_tegra_data *tspi = spi_master_get_devdata(master);
- clk_enable(tspi->sclk);
- clk_enable(tspi->clk);
- return 0;
+ return tegra_spi_clk_enable(tspi);
}
static const struct dev_pm_ops tegra_spi_dev_pm_ops = {
+#if defined(CONFIG_PM_RUNTIME)
.runtime_idle = tegra_spi_runtime_idle,
.runtime_resume = tegra_spi_runtime_resume,
-};
-
#endif
+#ifdef CONFIG_PM
+ .suspend = spi_tegra_suspend,
+ .resume = spi_tegra_resume,
+#endif
+};
MODULE_ALIAS("platform:spi_tegra");
@@ -1644,16 +1699,10 @@ static struct platform_driver spi_tegra_driver = {
.driver = {
.name = "spi_tegra",
.owner = THIS_MODULE,
-#if defined(CONFIG_PM_RUNTIME)
.pm = &tegra_spi_dev_pm_ops,
-#endif
.of_match_table = spi_tegra_of_match_table,
},
.remove = __devexit_p(spi_tegra_remove),
-#ifdef CONFIG_PM
- .suspend = spi_tegra_suspend,
- .resume = spi_tegra_resume,
-#endif
};
static int __init spi_tegra_init(void)
diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c
index f5c226cc1689..7d22559e54c4 100644
--- a/drivers/spi/spi-topcliff-pch.c
+++ b/drivers/spi/spi-topcliff-pch.c
@@ -1120,13 +1120,8 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw)
sg_dma_address(sg) = dma->tx_buf_dma + sg->offset;
}
sg = dma->sg_tx_p;
-<<<<<<< HEAD
- desc_tx = dma->chan_tx->device->device_prep_slave_sg(dma->chan_tx,
- sg, num, DMA_TO_DEVICE,
-=======
desc_tx = dmaengine_prep_slave_sg(dma->chan_tx,
sg, num, DMA_MEM_TO_DEV,
->>>>>>> 1605282... dmaengine/dma_slave: introduce inline wrappers
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc_tx) {
dev_err(&data->master->dev, "%s:device_prep_slave_sg Failed\n",
diff --git a/drivers/staging/iio/light/ltr558als.c b/drivers/staging/iio/light/ltr558als.c
index 01e410b191fd..4fef5d4cc034 100644
--- a/drivers/staging/iio/light/ltr558als.c
+++ b/drivers/staging/iio/light/ltr558als.c
@@ -193,7 +193,7 @@ static bool ltr558_set_proxim_high_threshold(struct i2c_client *client,
bool st;
st = ltr558_i2c_write_reg(client, LTR558_PS_THRES_UP_0,
thresh & 0xFF);
- if (st)
+ if (!st)
st = ltr558_i2c_write_reg(client, LTR558_PS_THRES_UP_1,
(thresh >> 8) & 0x07);
return st;
@@ -205,7 +205,7 @@ static bool ltr558_set_proxim_low_threshold(struct i2c_client *client,
bool st;
st = ltr558_i2c_write_reg(client, LTR558_PS_THRES_LOW_0,
thresh & 0xFF);
- if (st)
+ if (!st)
st = ltr558_i2c_write_reg(client, LTR558_PS_THRES_LOW_1,
(thresh >> 8) & 0x07);
return st;
@@ -216,7 +216,7 @@ static bool ltr558_set_als_high_threshold(struct i2c_client *client, u32 thresh)
bool st;
st = ltr558_i2c_write_reg(client, LTR558_ALS_THRES_UP_0,
thresh & 0xFF);
- if (st)
+ if (!st)
st = ltr558_i2c_write_reg(client, LTR558_ALS_THRES_UP_1,
(thresh >> 8) & 0xFF);
return st;
@@ -227,7 +227,7 @@ static bool ltr558_set_als_low_threshold(struct i2c_client *client, u32 thresh)
bool st;
st = ltr558_i2c_write_reg(client, LTR558_ALS_THRES_LOW_0,
thresh & 0xFF);
- if (st)
+ if (!st)
st = ltr558_i2c_write_reg(client, LTR558_ALS_THRES_LOW_1,
((thresh >> 8) & 0xFF));
return st;
@@ -314,7 +314,7 @@ static ssize_t store_proxim_low_threshold(struct device *dev,
mutex_lock(&chip->lock);
st = ltr558_set_proxim_low_threshold(client, (u8)lval);
- if (st)
+ if (!st)
chip->prox_low_thres = (int)lval;
else
dev_err(dev, "Error in setting proximity low threshold\n");
@@ -355,7 +355,7 @@ static ssize_t store_proxim_high_threshold(struct device *dev,
mutex_lock(&chip->lock);
st = ltr558_set_proxim_high_threshold(client, lval);
- if (st)
+ if (!st)
chip->prox_high_thres = (int)lval;
else
dev_err(dev, "Error in setting proximity high threshold\n");
@@ -443,7 +443,7 @@ static ssize_t store_als_low_threshold(struct device *dev,
mutex_lock(&chip->lock);
st = ltr558_set_als_low_threshold(client, (int)lval);
- if (st)
+ if (!st)
chip->als_low_thres = (int)lval;
else
dev_err(dev, "Error in setting als low threshold\n");
@@ -483,7 +483,7 @@ static ssize_t store_als_high_threshold(struct device *dev,
mutex_lock(&chip->lock);
st = ltr558_set_als_high_threshold(client, (int)lval);
- if (st)
+ if (!st)
chip->als_high_thres = (int)lval;
else
dev_err(dev, "Error in setting als high threshold\n");
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index df8c8faad106..f20c82aa6d28 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -673,14 +673,9 @@ static int pl011_dma_rx_trigger_dma(struct uart_amba_port *uap)
/* Start the RX DMA job */
sgbuf = uap->dmarx.use_buf_b ?
&uap->dmarx.sgbuf_b : &uap->dmarx.sgbuf_a;
-<<<<<<< HEAD
dma_dev = rxchan->device;
- desc = rxchan->device->device_prep_slave_sg(rxchan, &sgbuf->sg, 1,
- DMA_FROM_DEVICE,
-=======
desc = dmaengine_prep_slave_sg(rxchan, &sgbuf->sg, 1,
DMA_DEV_TO_MEM,
->>>>>>> 1605282... dmaengine/dma_slave: introduce inline wrappers
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
/*
* If the DMA engine is busy and cannot prepare a
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index 5c33cefe2953..9748681679eb 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -910,13 +910,8 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv)
sg_dma_len(sg) = size;
}
-<<<<<<< HEAD
- desc = priv->chan_tx->device->device_prep_slave_sg(priv->chan_tx,
- priv->sg_tx_p, nent, DMA_TO_DEVICE,
-=======
desc = dmaengine_prep_slave_sg(priv->chan_tx,
priv->sg_tx_p, nent, DMA_MEM_TO_DEV,
->>>>>>> 1605282... dmaengine/dma_slave: introduce inline wrappers
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc) {
dev_err(priv->port.dev, "%s:device_prep_slave_sg Failed\n",
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 3f4d9193b645..ef49f0a08364 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -1328,13 +1328,8 @@ static void work_fn_tx(struct work_struct *work)
BUG_ON(!sg_dma_len(sg));
-<<<<<<< HEAD
- desc = chan->device->device_prep_slave_sg(chan,
- sg, s->sg_len_tx, DMA_TO_DEVICE,
-=======
desc = dmaengine_prep_slave_sg(chan,
sg, s->sg_len_tx, DMA_MEM_TO_DEV,
->>>>>>> 1605282... dmaengine/dma_slave: introduce inline wrappers
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc) {
/* switch to PIO */
diff --git a/drivers/tty/serial/tegra_hsuart.c b/drivers/tty/serial/tegra_hsuart.c
index 10560107e066..ea20de6ebb41 100644
--- a/drivers/tty/serial/tegra_hsuart.c
+++ b/drivers/tty/serial/tegra_hsuart.c
@@ -155,14 +155,6 @@ static inline void uart_writeb(struct tegra_uart_port *t, u8 val,
writeb(val, t->uport.membase + (reg << t->uport.regshift));
}
-static void cancel_dma(struct tegra_dma_channel *dma_chan,
- struct tegra_dma_req *req)
-{
- tegra_dma_cancel(dma_chan);
- if (req->status == -TEGRA_DMA_REQ_ERROR_ABORTED)
- req->complete(req);
-}
-
static inline void uart_writel(struct tegra_uart_port *t, u32 val,
unsigned long reg)
{
@@ -352,7 +344,7 @@ static void do_handle_rx_dma(struct tegra_uart_port *t)
struct uart_port *u = &t->uport;
if (t->rts_active)
set_rts(t, false);
- cancel_dma(t->rx_dma, &t->rx_dma_req);
+ tegra_dma_dequeue_req(t->rx_dma, &t->rx_dma_req);
tty_flip_buffer_push(u->state->port.tty);
/* enqueue the request again */
tegra_start_dma_rx(t);
@@ -628,7 +620,7 @@ static void tegra_stop_rx(struct uart_port *u)
t->rx_in_progress = 0;
if (t->use_rx_dma && t->rx_dma)
- cancel_dma(t->rx_dma, &t->rx_dma_req);
+ tegra_dma_dequeue_req(t->rx_dma, &t->rx_dma_req);
else
do_handle_rx_pio(t);
@@ -903,7 +895,7 @@ static int tegra_startup(struct uart_port *u)
goto fail;
pdata = u->dev->platform_data;
- if (pdata->is_loopback)
+ if (pdata && pdata->is_loopback)
t->mcr_shadow |= UART_MCR_LOOP;
dev_dbg(u->dev, "Requesting IRQ %d\n", u->irq);
@@ -1077,7 +1069,7 @@ static void tegra_stop_tx(struct uart_port *u)
t = container_of(u, struct tegra_uart_port, uport);
if (t->use_tx_dma)
- cancel_dma(t->tx_dma, &t->tx_dma_req);
+ tegra_dma_dequeue_req(t->tx_dma, &t->tx_dma_req);
return;
}
@@ -1271,6 +1263,12 @@ static void tegra_set_termios(struct uart_port *u, struct ktermios *termios,
if (t->rts_active)
set_rts(t, false);
+ /* Clear all interrupts as configuration is going to be change */
+ uart_writeb(t, t->ier_shadow | UART_IER_RDI, UART_IER);
+ uart_readb(t, UART_IER);
+ uart_writeb(t, 0, UART_IER);
+ uart_readb(t, UART_IER);
+
/* Parity */
lcr = t->lcr_shadow;
lcr &= ~UART_LCR_PARITY;
@@ -1343,6 +1341,13 @@ static void tegra_set_termios(struct uart_port *u, struct ktermios *termios,
/* update the port timeout based on new settings */
uart_update_timeout(u, termios->c_cflag, baud);
+ /* Make sure all write has completed */
+ uart_readb(t, UART_IER);
+
+ /* Reenable interrupt */
+ uart_writeb(t, t->ier_shadow, UART_IER);
+ uart_readb(t, UART_IER);
+
spin_unlock_irqrestore(&u->lock, flags);
dev_vdbg(t->uport.dev, "-tegra_set_termios\n");
return;
@@ -1363,7 +1368,7 @@ static void tegra_flush_buffer(struct uart_port *u)
t->tx_bytes = 0;
if (t->use_tx_dma) {
- cancel_dma(t->tx_dma, &t->tx_dma_req);
+ tegra_dma_dequeue_req(t->tx_dma, &t->tx_dma_req);
t->tx_dma_req.size = 0;
}
return;
@@ -1646,7 +1651,7 @@ int tegra_uart_is_tx_empty(struct uart_port *uport)
return tegra_tx_empty(uport);
}
-static struct platform_driver tegra_uart_platform_driver = {
+static struct platform_driver tegra_uart_platform_driver __refdata= {
.probe = tegra_uart_probe,
.remove = __devexit_p(tegra_uart_remove),
.suspend = tegra_uart_suspend,
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index f92c3df69195..8e051d72d6aa 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -178,6 +178,17 @@ config USB_OMAP
dynamically linked module called "omap_udc" and force all
gadget drivers to also be dynamically linked.
+config USB_TEGRA
+ tristate "Nvidia Highspeed USB 2.0 device controller"
+ depends on ARCH_TEGRA
+ select USB_GADGET_DUALSPEED
+ help
+ Enables TEGRA USB 2.0 pheripheral driver.
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "tegra_udc" and force all
+ gadget drivers to also be dynamically linked.
+
config USB_PXA25X
tristate "PXA 25x or IXP 4xx"
depends on (ARCH_PXA && PXA25x) || ARCH_IXP4XX
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 581a5ae7337e..c8c7c687010d 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -1,8 +1,7 @@
#
# USB peripheral controller drivers
#
-GCOV_PROFILE_fsl_tegra_udc.o := y
-GCOV_PROFILE_fsl_udc_core.o := y
+GCOV_PROFILE_tegra_udc.o := y
ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG
@@ -22,7 +21,7 @@ obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o
obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o
fsl_usb2_udc-y := fsl_udc_core.o
fsl_usb2_udc-$(CONFIG_ARCH_MXC) += fsl_mxc_udc.o
-fsl_usb2_udc-$(CONFIG_ARCH_TEGRA) += fsl_tegra_udc.o
+obj-$(CONFIG_USB_TEGRA) += tegra_udc.o
obj-$(CONFIG_USB_M66592) += m66592-udc.o
obj-$(CONFIG_USB_R8A66597) += r8a66597-udc.o
obj-$(CONFIG_USB_FSL_QE) += fsl_qe_udc.o
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index fbafe8a3bca4..4805670cf6e3 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -319,6 +319,13 @@ static int mtp_function_ctrlrequest(struct android_usb_function *f,
return mtp_ctrlrequest(cdev, c);
}
+static int ptp_function_ctrlrequest(struct android_usb_function *f,
+ struct usb_composite_dev *cdev,
+ const struct usb_ctrlrequest *c)
+{
+ return mtp_ctrlrequest(cdev, c);
+}
+
static struct android_usb_function mtp_function = {
.name = "mtp",
.init = mtp_function_init,
@@ -333,6 +340,7 @@ static struct android_usb_function ptp_function = {
.init = ptp_function_init,
.cleanup = ptp_function_cleanup,
.bind_config = ptp_function_bind_config,
+ .ctrlrequest = ptp_function_ctrlrequest,
};
diff --git a/drivers/usb/gadget/fsl_tegra_udc.c b/drivers/usb/gadget/fsl_tegra_udc.c
deleted file mode 100644
index 31b476ad2279..000000000000
--- a/drivers/usb/gadget/fsl_tegra_udc.c
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Description:
- * Helper functions to support the tegra USB controller
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the 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/fsl_devices.h>
-#include <linux/platform_device.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <mach/usb_phy.h>
-
-static struct tegra_usb_phy *phy;
-static struct clk *udc_clk;
-static struct clk *emc_clk;
-static struct clk *sclk_clk;
-static void *udc_base;
-
-int fsl_udc_clk_init(struct platform_device *pdev)
-{
- struct resource *res;
- int err;
- int instance;
- struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
-
-
- udc_clk = clk_get(&pdev->dev, NULL);
- if (IS_ERR(udc_clk)) {
- dev_err(&pdev->dev, "Can't get udc clock\n");
- return PTR_ERR(udc_clk);
- }
-
- clk_enable(udc_clk);
-
- sclk_clk = clk_get(&pdev->dev, "sclk");
- if (IS_ERR(sclk_clk)) {
- dev_err(&pdev->dev, "Can't get sclk clock\n");
- err = PTR_ERR(sclk_clk);
- goto err_sclk;
- }
-
- clk_set_rate(sclk_clk, 80000000);
- clk_enable(sclk_clk);
-
- emc_clk = clk_get(&pdev->dev, "emc");
- if (IS_ERR(emc_clk)) {
- dev_err(&pdev->dev, "Can't get emc clock\n");
- err = PTR_ERR(emc_clk);
- goto err_emc;
- }
-
- clk_enable(emc_clk);
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- /* Set DDR busy hints to 150MHz. For Tegra 2x SOC, DDR rate is half of EMC rate */
- clk_set_rate(emc_clk, 300000000);
-#else
- /* Set DDR busy hints to 100MHz. For Tegra 3x SOC DDR rate equals to EMC rate */
- clk_set_rate(emc_clk, 100000000);
-#endif
-
- /* we have to remap the registers ourselves as fsl_udc does not
- * export them for us.
- */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- err = -ENXIO;
- goto err0;
- }
- udc_base = ioremap(res->start, resource_size(res));
- if (!udc_base) {
- err = -ENOMEM;
- goto err0;
- }
-
- instance = pdev->id;
- if (instance == -1)
- instance = 0;
-
- phy = tegra_usb_phy_open(instance, udc_base, pdata->phy_config,
- TEGRA_USB_PHY_MODE_DEVICE, pdata->usb_phy_type);
- if (IS_ERR(phy)) {
- dev_err(&pdev->dev, "Can't open phy\n");
- err = PTR_ERR(phy);
- goto err1;
- }
- tegra_usb_phy_power_on(phy, true);
-
- return 0;
-err1:
- iounmap(udc_base);
-err0:
- clk_disable(emc_clk);
- clk_put(emc_clk);
-err_emc:
- clk_disable(sclk_clk);
- clk_put(sclk_clk);
-err_sclk:
- clk_disable(udc_clk);
- clk_put(udc_clk);
- return err;
-}
-
-void fsl_udc_clk_finalize(struct platform_device *pdev)
-{
-}
-
-void fsl_udc_clk_release(void)
-{
- tegra_usb_phy_close(phy);
-
- iounmap(udc_base);
-
- clk_disable(udc_clk);
- clk_put(udc_clk);
-
- clk_disable(sclk_clk);
- clk_put(sclk_clk);
-
- clk_disable(emc_clk);
- clk_put(emc_clk);
-}
-
-void fsl_udc_clk_suspend(bool is_dpd)
-{
- tegra_usb_phy_power_off(phy, is_dpd);
- clk_disable(udc_clk);
- clk_disable(sclk_clk);
- clk_disable(emc_clk);
-}
-
-void fsl_udc_clk_resume(bool is_dpd)
-{
- clk_enable(emc_clk);
- clk_enable(sclk_clk);
- clk_enable(udc_clk);
- tegra_usb_phy_power_on(phy, is_dpd);
-}
-
-void fsl_udc_clk_enable(void)
-{
- clk_enable(udc_clk);
-}
-
-void fsl_udc_clk_disable(void)
-{
- clk_disable(udc_clk);
-}
-
-bool fsl_udc_charger_detect(void)
-{
- return tegra_usb_phy_charger_detect(phy);
-}
-
-void fsl_udc_dtd_prepare(void)
-{
- /* When we are programming two DTDs very close to each other,
- * the second DTD is being prefetched before it is actually written
- * to DDR. To prevent this, we disable prefetcher before programming
- * any new DTD and re-enable it before priming endpoint.
- */
- tegra_usb_phy_memory_prefetch_off(phy);
-}
-
-void fsl_udc_ep_barrier(void)
-{
- tegra_usb_phy_memory_prefetch_on(phy);
-}
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index f3a83cd0ef50..db7f521e5d0a 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -49,6 +49,7 @@
#define gadget_is_s3c2410(g) (!strcmp("s3c2410_udc", (g)->name))
#define gadget_is_s3c_hsotg(g) (!strcmp("s3c-hsotg", (g)->name))
#define gadget_is_s3c_hsudc(g) (!strcmp("s3c-hsudc", (g)->name))
+#define gadget_is_tegra(g) (!strcmp("tegra-udc", (g)->name))
/**
* usb_gadget_controller_number - support bcdDevice id convention
@@ -115,7 +116,8 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
return 0x30;
else if (gadget_is_net2272(gadget))
return 0x31;
-
+ else if (gadget_is_tegra(gadget))
+ return 0x32;
return -ENOENT;
}
diff --git a/drivers/usb/gadget/tegra_udc.c b/drivers/usb/gadget/tegra_udc.c
new file mode 100644
index 000000000000..aad99a6cd66e
--- /dev/null
+++ b/drivers/usb/gadget/tegra_udc.c
@@ -0,0 +1,2790 @@
+/*
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * Description:
+ * High-speed USB device controller driver.
+ * The driver is based on Freescale driver code from Li Yang and Jiang Bo.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the 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 VERBOSE
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/mm.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/dmapool.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+#include <linux/workqueue.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/pm_qos_params.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+#include <asm/dma.h>
+
+#include <mach/usb_phy.h>
+#include <mach/iomap.h>
+
+#include "tegra_udc.h"
+
+
+#define DRIVER_DESC "Nvidia Tegra High-Speed USB SOC \
+ Device Controller driver"
+
+#define DRIVER_AUTHOR "Venkat Moganty/Rakesh Bodla"
+#define DRIVER_VERSION "Apr 30, 2012"
+#define USB1_PREFETCH_ID 6
+
+#define get_ep_by_pipe(udc, pipe) ((pipe == 1) ? &udc->eps[0] : \
+ &udc->eps[pipe])
+#define get_pipe_by_windex(windex) ((windex & USB_ENDPOINT_NUMBER_MASK) \
+ * 2 + ((windex & USB_DIR_IN) ? 1 : 0))
+
+#define ep_index(EP) ((EP)->desc->bEndpointAddress&0xF)
+#define ep_is_in(EP) ((ep_index(EP) == 0) ? (EP->udc->ep0_dir == \
+ USB_DIR_IN) : ((EP)->desc->bEndpointAddress \
+ & USB_DIR_IN) == USB_DIR_IN)
+
+
+static const char driver_name[] = "tegra-udc";
+static const char driver_desc[] = DRIVER_DESC;
+
+static void tegra_ep_fifo_flush(struct usb_ep *_ep);
+static int reset_queues(struct tegra_udc *udc);
+
+/*
+ * High speed test mode packet(53 bytes).
+ * See USB 2.0 spec, section 7.1.20.
+ */
+static const u8 tegra_udc_test_packet[53] = {
+ /* JKJKJKJK x9 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* JJKKJJKK x8 */
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ /* JJJJKKKK x8 */
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ /* JJJJJJJKKKKKKK x8 */
+ 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* JJJJJJJK x8 */
+ 0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd,
+ /* JKKKKKKK x10, JK */
+ 0xfc, 0x7e, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0x7e
+};
+
+static struct tegra_udc *the_udc;
+
+#ifdef CONFIG_TEGRA_GADGET_BOOST_CPU_FREQ
+ static struct pm_qos_request_list boost_cpu_freq_req;
+ static u32 ep_queue_request_count;
+ static u8 boost_cpufreq_work_flag;
+#endif
+
+static inline void udc_writel(struct tegra_udc *udc, u32 val, u32 offset)
+{
+ writel(val, udc->regs + offset);
+}
+
+static inline unsigned int udc_readl(struct tegra_udc *udc, u32 offset)
+{
+ return readl(udc->regs + offset);
+}
+
+/* checks vbus status */
+static inline bool vbus_enabled(struct tegra_udc *udc)
+{
+ bool status = false;
+ status = (udc_readl(udc, VBUS_WAKEUP_REG_OFFSET) & USB_SYS_VBUS_STATUS);
+ return status;
+}
+
+/**
+ * done() - retire a request; caller blocked irqs
+ * @status : request status to be set, only works when
+ * request is still in progress.
+ */
+static void done(struct tegra_ep *ep, struct tegra_req *req, int status)
+{
+ struct tegra_udc *udc = NULL;
+ unsigned char stopped = ep->stopped;
+ struct ep_td_struct *curr_td, *next_td;
+ int j;
+ BUG_ON(!(in_irq() || irqs_disabled()));
+ udc = (struct tegra_udc *)ep->udc;
+ /* Removed the req from tegra_ep->queue */
+ list_del_init(&req->queue);
+
+ /* req.status should be set as -EINPROGRESS in ep_queue() */
+ if (req->req.status == -EINPROGRESS)
+ req->req.status = status;
+ else
+ status = req->req.status;
+
+ /* Free dtd for the request */
+ next_td = req->head;
+ for (j = 0; j < req->dtd_count; j++) {
+ curr_td = next_td;
+ if (j != req->dtd_count - 1)
+ next_td = curr_td->next_td_virt;
+
+ dma_pool_free(udc->td_pool, curr_td, curr_td->td_dma);
+ }
+
+ if (req->mapped) {
+ dma_unmap_single(ep->udc->gadget.dev.parent,
+ req->req.dma, req->req.length,
+ ep_is_in(ep)
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+ req->req.dma = DMA_ADDR_INVALID;
+ req->mapped = 0;
+ } else
+ dma_sync_single_for_cpu(ep->udc->gadget.dev.parent,
+ req->req.dma, req->req.length,
+ ep_is_in(ep)
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+
+ if (status && (status != -ESHUTDOWN))
+ VDBG("complete %s req %p stat %d len %u/%u",
+ ep->ep.name, &req->req, status,
+ req->req.actual, req->req.length);
+
+ ep->stopped = 1;
+#ifdef CONFIG_TEGRA_GADGET_BOOST_CPU_FREQ
+ if (req->req.complete && req->req.length >= BOOST_TRIGGER_SIZE) {
+ ep_queue_request_count--;
+ if (!ep_queue_request_count)
+ schedule_work(&udc->boost_cpufreq_work);
+ }
+#endif
+
+ /* complete() is from gadget layer,
+ * eg fsg->bulk_in_complete() */
+ if (req->req.complete) {
+ spin_unlock(&ep->udc->lock);
+ req->req.complete(&ep->ep, &req->req);
+ spin_lock(&ep->udc->lock);
+ }
+
+ ep->stopped = stopped;
+}
+
+/*
+ * nuke(): delete all requests related to this ep
+ * Must be called with spinlock held and interrupt disabled
+ */
+static void nuke(struct tegra_ep *ep, int status)
+{
+ ep->stopped = 1;
+
+ /* Flush fifo */
+ tegra_ep_fifo_flush(&ep->ep);
+
+ /* Whether this eq has request linked */
+ while (!list_empty(&ep->queue)) {
+ struct tegra_req *req = NULL;
+
+ req = list_entry(ep->queue.next, struct tegra_req, queue);
+ done(ep, req, status);
+ }
+}
+
+static int can_pullup(struct tegra_udc *udc)
+{
+ DBG("%s(%d) udc->softconnect = %d udc->vbus_active = %d\n",
+ __func__, __LINE__, udc->softconnect, udc->vbus_active);
+ return udc->driver && udc->softconnect && udc->vbus_active;
+}
+
+static int dr_controller_reset(struct tegra_udc *udc)
+{
+ unsigned int tmp;
+ unsigned long timeout;
+ DBG("%s(%d) BEGIN\n", __func__, __LINE__);
+
+ /* Stop and reset the usb controller */
+ tmp = udc_readl(udc, USB_CMD_REG_OFFSET);
+ tmp &= ~USB_CMD_RUN_STOP;
+ udc_writel(udc, tmp, USB_CMD_REG_OFFSET);
+
+ tmp = udc_readl(udc, USB_CMD_REG_OFFSET);
+ tmp |= USB_CMD_CTRL_RESET;
+ udc_writel(udc, tmp, USB_CMD_REG_OFFSET);
+
+ /* Wait for reset to complete */
+ timeout = jiffies + UDC_RESET_TIMEOUT_MS;
+ while (udc_readl(udc, USB_CMD_REG_OFFSET) & USB_CMD_CTRL_RESET) {
+ if (time_after(jiffies, timeout)) {
+ ERR("udc reset timeout!\n");
+ return -ETIMEDOUT;
+ }
+ cpu_relax();
+ }
+
+ DBG("%s(%d) END\n", __func__, __LINE__);
+ return 0;
+}
+
+static int dr_controller_setup(struct tegra_udc *udc)
+{
+ unsigned int tmp, portctrl;
+ unsigned long timeout;
+ int status;
+ unsigned int port_control_reg_offset;
+ DBG("%s(%d) BEGIN\n", __func__, __LINE__);
+
+ if (udc->has_hostpc)
+ port_control_reg_offset = USB_HOSTPCX_DEVLC_REG_OFFSET;
+ else
+ port_control_reg_offset = PORTSCX_REG_OFFSET;
+
+ /* Config PHY interface */
+ portctrl = udc_readl(udc, port_control_reg_offset);
+ portctrl &= ~(PORTSCX_PHY_TYPE_SEL | PORTSCX_PORT_WIDTH);
+ portctrl |= PORTSCX_PTS_UTMI;
+ udc_writel(udc, portctrl, port_control_reg_offset);
+
+ status = dr_controller_reset(udc);
+ if (status)
+ return status;
+
+ /* Set the controller as device mode */
+ tmp = udc_readl(udc, USB_MODE_REG_OFFSET);
+ tmp |= USB_MODE_CTRL_MODE_DEVICE;
+ /* Disable Setup Lockout */
+ tmp |= USB_MODE_SETUP_LOCK_OFF;
+ udc_writel(udc, tmp, USB_MODE_REG_OFFSET);
+
+ /* Wait for controller to switch to device mode */
+ timeout = jiffies + UDC_RESET_TIMEOUT_MS;
+ while ((udc_readl(udc, USB_MODE_REG_OFFSET) &
+ USB_MODE_CTRL_MODE_DEVICE) != USB_MODE_CTRL_MODE_DEVICE) {
+ if (time_after(jiffies, timeout)) {
+ ERR("udc device mode setup timeout!\n");
+ return -ETIMEDOUT;
+ }
+ cpu_relax();
+ }
+
+ /* Clear the setup status */
+ udc_writel(udc, 0, USB_STS_REG_OFFSET);
+
+ tmp = udc->ep_qh_dma;
+ tmp &= USB_EP_LIST_ADDRESS_MASK;
+ udc_writel(udc, tmp, USB_EP_LIST_ADDRESS_REG_OFFSET);
+
+ VDBG("vir[qh_base] is %p phy[qh_base] is 0x%8x reg is 0x%8x",
+ udc->ep_qh, (int)tmp,
+ udc_readl(udc, USB_EP_LIST_ADDRESS_REG_OFFSET));
+
+ DBG("%s(%d) END\n", __func__, __LINE__);
+ return 0;
+}
+
+/* Enable DR irq and set controller to run state */
+static void dr_controller_run(struct tegra_udc *udc)
+{
+ u32 temp;
+ unsigned long timeout;
+ DBG("%s(%d) BEGIN\n", __func__, __LINE__);
+
+ /* Clear stopped bit */
+ udc->stopped = 0;
+
+ /* If OTG transceiver is available, then it handles the VBUS detection*/
+ if (!udc->transceiver) {
+ /* Enable cable detection interrupt, without setting the
+ * USB_SYS_VBUS_WAKEUP_INT bit. USB_SYS_VBUS_WAKEUP_INT is
+ * clear on write */
+ temp = udc_readl(udc, VBUS_WAKEUP_REG_OFFSET);
+ temp |= (USB_SYS_VBUS_WAKEUP_INT_ENABLE
+ | USB_SYS_VBUS_WAKEUP_ENABLE);
+ temp &= ~USB_SYS_VBUS_WAKEUP_INT_STATUS;
+ udc_writel(udc, temp, VBUS_WAKEUP_REG_OFFSET);
+ }
+ /* Enable DR irq reg */
+ temp = USB_INTR_INT_EN | USB_INTR_ERR_INT_EN
+ | USB_INTR_PTC_DETECT_EN | USB_INTR_RESET_EN
+ | USB_INTR_DEVICE_SUSPEND | USB_INTR_SYS_ERR_EN;
+
+ udc_writel(udc, temp, USB_INTR_REG_OFFSET);
+
+ /* Set the controller as device mode */
+ temp = udc_readl(udc, USB_MODE_REG_OFFSET);
+ temp |= USB_MODE_CTRL_MODE_DEVICE;
+ udc_writel(udc, temp, USB_MODE_REG_OFFSET);
+
+ /* Set controller to Run */
+ temp = udc_readl(udc, USB_CMD_REG_OFFSET);
+ if (can_pullup(udc))
+ temp |= USB_CMD_RUN_STOP;
+ else
+ temp &= ~USB_CMD_RUN_STOP;
+ udc_writel(udc, temp, USB_CMD_REG_OFFSET);
+
+ if (can_pullup(udc)) {
+ /* Wait for controller to start */
+ timeout = jiffies + UDC_RUN_TIMEOUT_MS;
+ while ((udc_readl(udc, USB_CMD_REG_OFFSET) & USB_CMD_RUN_STOP)
+ != USB_CMD_RUN_STOP) {
+ if (time_after(jiffies, timeout)) {
+ ERR("udc start timeout!\n");
+ return;
+ }
+ cpu_relax();
+ }
+ }
+
+ DBG("%s(%d) END\n", __func__, __LINE__);
+ return;
+}
+
+static void dr_controller_stop(struct tegra_udc *udc)
+{
+ unsigned int tmp;
+ DBG("%s(%d) BEGIN\n", __func__, __LINE__);
+
+ /* Clear pending interrupt status bits */
+ tmp = udc_readl(udc, USB_STS_REG_OFFSET);
+ udc_writel(udc, tmp, USB_STS_REG_OFFSET);
+
+ /* disable all INTR */
+ udc_writel(udc, 0, USB_INTR_REG_OFFSET);
+
+ /* Set stopped bit for isr */
+ udc->stopped = 1;
+
+ /* set controller to Stop */
+ tmp = udc_readl(udc, USB_CMD_REG_OFFSET);
+ tmp &= ~USB_CMD_RUN_STOP;
+ udc_writel(udc, tmp, USB_CMD_REG_OFFSET);
+
+ DBG("%s(%d) END\n", __func__, __LINE__);
+ return;
+}
+
+static void dr_ep_setup(struct tegra_udc *udc, unsigned char ep_num,
+ unsigned char dir, unsigned char ep_type)
+{
+ unsigned int tmp_epctrl = 0;
+
+ tmp_epctrl = udc_readl(udc, EP_CONTROL_REG_OFFSET + (ep_num * 4));
+ if (dir) {
+ if (ep_num)
+ tmp_epctrl |= EPCTRL_TX_DATA_TOGGLE_RST;
+ tmp_epctrl |= EPCTRL_TX_ENABLE;
+ tmp_epctrl |= ((unsigned int)(ep_type)
+ << EPCTRL_TX_EP_TYPE_SHIFT);
+ } else {
+ if (ep_num)
+ tmp_epctrl |= EPCTRL_RX_DATA_TOGGLE_RST;
+ tmp_epctrl |= EPCTRL_RX_ENABLE;
+ tmp_epctrl |= ((unsigned int)(ep_type)
+ << EPCTRL_RX_EP_TYPE_SHIFT);
+ }
+
+ udc_writel(udc, tmp_epctrl, EP_CONTROL_REG_OFFSET + (ep_num * 4));
+}
+
+static void dr_ep_change_stall(struct tegra_udc *udc, unsigned char ep_num,
+ unsigned char dir, int value)
+{
+ u32 tmp_epctrl = 0;
+
+ tmp_epctrl = udc_readl(udc, EP_CONTROL_REG_OFFSET + (ep_num * 4));
+ if (value) {
+ /* set the stall bit */
+ if (dir)
+ tmp_epctrl |= EPCTRL_TX_EP_STALL;
+ else
+ tmp_epctrl |= EPCTRL_RX_EP_STALL;
+ } else {
+ /* clear the stall bit and reset data toggle */
+ if (dir) {
+ tmp_epctrl &= ~EPCTRL_TX_EP_STALL;
+ tmp_epctrl |= EPCTRL_TX_DATA_TOGGLE_RST;
+ } else {
+ tmp_epctrl &= ~EPCTRL_RX_EP_STALL;
+ tmp_epctrl |= EPCTRL_RX_DATA_TOGGLE_RST;
+ }
+ }
+ udc_writel(udc, tmp_epctrl, EP_CONTROL_REG_OFFSET + (ep_num * 4));
+}
+
+/* Get stall status of a specific ep
+ Return: 0: not stalled; 1:stalled */
+static int dr_ep_get_stall(struct tegra_udc *udc, unsigned char ep_num,
+ unsigned char dir)
+{
+ u32 epctrl;
+
+ epctrl = udc_readl(udc, EP_CONTROL_REG_OFFSET + (ep_num * 4));
+ if (dir)
+ return (epctrl & EPCTRL_TX_EP_STALL) ? 1 : 0;
+ else
+ return (epctrl & EPCTRL_RX_EP_STALL) ? 1 : 0;
+}
+
+/**
+ * struct_ep_qh_setup(): set the Endpoint Capabilites field of QH
+ * @zlt: Zero Length Termination Select (1: disable; 0: enable)
+ * @mult: Mult field
+ */
+static void struct_ep_qh_setup(struct tegra_udc *udc, unsigned char ep_num,
+ unsigned char dir, unsigned char ep_type,
+ unsigned int max_pkt_len, unsigned int zlt, unsigned char mult)
+{
+ struct ep_queue_head *p_QH = &udc->ep_qh[2 * ep_num + dir];
+ unsigned int tmp = 0;
+
+ /* set the Endpoint Capabilites in QH */
+ switch (ep_type) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ /* Interrupt On Setup (IOS). for control ep */
+ tmp = (max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS)
+ | EP_QUEUE_HEAD_IOS;
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ tmp = (max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS)
+ | (mult << EP_QUEUE_HEAD_MULT_POS);
+ break;
+ case USB_ENDPOINT_XFER_BULK:
+ case USB_ENDPOINT_XFER_INT:
+ tmp = max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS;
+ break;
+ default:
+ VDBG("error ep type is %d", ep_type);
+ return;
+ }
+ if (zlt)
+ tmp |= EP_QUEUE_HEAD_ZLT_SEL;
+
+ p_QH->max_pkt_length = cpu_to_le32(tmp);
+ p_QH->next_dtd_ptr = 1;
+ p_QH->size_ioc_int_sts = 0;
+
+ return;
+}
+
+/* Setup qh structure and ep register for ep0. */
+static void ep0_setup(struct tegra_udc *udc)
+{
+ /* the intialization of an ep includes: fields in QH, Regs,
+ * tegra_ep struct */
+ struct_ep_qh_setup(udc, 0, USB_RECV, USB_ENDPOINT_XFER_CONTROL,
+ USB_MAX_CTRL_PAYLOAD, 1, 0);
+ struct_ep_qh_setup(udc, 0, USB_SEND, USB_ENDPOINT_XFER_CONTROL,
+ USB_MAX_CTRL_PAYLOAD, 1, 0);
+ dr_ep_setup(udc, 0, USB_RECV, USB_ENDPOINT_XFER_CONTROL);
+ dr_ep_setup(udc, 0, USB_SEND, USB_ENDPOINT_XFER_CONTROL);
+
+ return;
+
+}
+
+/**
+ * when configurations are set, or when interface settings change
+ * for example the do_set_interface() in gadget layer,
+ * the driver will enable or disable the relevant endpoints
+ * ep0 doesn't use this routine. It is always enabled.
+ */
+static int tegra_ep_enable(struct usb_ep *_ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct tegra_udc *udc = NULL;
+ struct tegra_ep *ep = NULL;
+ unsigned short max = 0;
+ unsigned char mult = 0, zlt;
+ int retval = -EINVAL;
+ unsigned long flags = 0;
+
+ ep = container_of(_ep, struct tegra_ep, ep);
+
+ /* catch various bogus parameters */
+ if (!_ep || !desc || ep->desc
+ || (desc->bDescriptorType != USB_DT_ENDPOINT))
+ return -EINVAL;
+
+ udc = ep->udc;
+
+ if (!udc->driver || (udc->gadget.speed == USB_SPEED_UNKNOWN))
+ return -ESHUTDOWN;
+
+ max = le16_to_cpu(desc->wMaxPacketSize);
+
+ /* Disable automatic zlp generation. Driver is responsible to indicate
+ * explicitly through req->req.zero. This is needed to enable multi-td
+ * request.
+ */
+ zlt = 1;
+
+ /* Assume the max packet size from gadget is always correct */
+ switch (desc->bmAttributes & 0x03) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ case USB_ENDPOINT_XFER_BULK:
+ case USB_ENDPOINT_XFER_INT:
+ /* mult = 0. Execute N Transactions as demonstrated by
+ * the USB variable length packet protocol where N is
+ * computed using the Maximum Packet Length (dQH) and
+ * the Total Bytes field (dTD) */
+ mult = 0;
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ /* Calculate transactions needed for high bandwidth iso */
+ mult = (unsigned char)(1 + ((max >> 11) & 0x03));
+ max = max & 0x7ff; /* bit 0~10 */
+ /* 3 transactions at most */
+ if (mult > 3)
+ goto en_done;
+ break;
+ default:
+ goto en_done;
+ }
+
+ spin_lock_irqsave(&udc->lock, flags);
+ ep->ep.maxpacket = max;
+ ep->desc = desc;
+ ep->stopped = 0;
+
+ /* Controller related setup
+ * Init EPx Queue Head (Ep Capabilites field in QH
+ * according to max, zlt, mult)
+ */
+ struct_ep_qh_setup(udc, (unsigned char) ep_index(ep),
+ (unsigned char) ((desc->bEndpointAddress & USB_DIR_IN)
+ ? USB_SEND : USB_RECV),
+ (unsigned char) (desc->bmAttributes
+ & USB_ENDPOINT_XFERTYPE_MASK),
+ max, zlt, mult);
+
+ /* Init endpoint ctrl register */
+ dr_ep_setup(udc, (unsigned char) ep_index(ep),
+ (unsigned char) ((desc->bEndpointAddress & USB_DIR_IN)
+ ? USB_SEND : USB_RECV),
+ (unsigned char) (desc->bmAttributes
+ & USB_ENDPOINT_XFERTYPE_MASK));
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+ retval = 0;
+
+ VDBG("enabled %s (ep%d%s) maxpacket %d", ep->ep.name,
+ ep->desc->bEndpointAddress & 0x0f,
+ (desc->bEndpointAddress & USB_DIR_IN)
+ ? "in" : "out", max);
+en_done:
+ return retval;
+}
+
+/**
+ * @ep : the ep being unconfigured. May not be ep0
+ * Any pending and uncomplete req will complete with status (-ESHUTDOWN)
+ */
+static int tegra_ep_disable(struct usb_ep *_ep)
+{
+ struct tegra_udc *udc = NULL;
+ struct tegra_ep *ep = NULL;
+
+ unsigned long flags = 0;
+ u32 epctrl;
+ int ep_num;
+
+ ep = container_of(_ep, struct tegra_ep, ep);
+ if (!_ep || !ep->desc) {
+ VDBG("%s not enabled", _ep ? ep->ep.name : NULL);
+ return -EINVAL;
+ }
+ udc = (struct tegra_udc *)ep->udc;
+
+ /* disable ep on controller */
+ ep_num = ep_index(ep);
+
+ /* Touch the registers if cable is connected and phy is on */
+ if (vbus_enabled(udc)) {
+ epctrl = udc_readl(udc, EP_CONTROL_REG_OFFSET + (ep_num * 4));
+ if (ep_is_in(ep))
+ epctrl &= ~EPCTRL_TX_ENABLE;
+ else
+ epctrl &= ~EPCTRL_RX_ENABLE;
+ udc_writel(udc, epctrl, EP_CONTROL_REG_OFFSET + (ep_num * 4));
+ }
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ /* nuke all pending requests (does flush) */
+ nuke(ep, -ESHUTDOWN);
+
+ ep->desc = NULL;
+ ep->stopped = 1;
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ VDBG("disabled %s OK", _ep->name);
+ return 0;
+}
+
+/**
+ * Allocate a request object used by this endpoint
+ * the main operation is to insert the req->queue to the eq->queue
+ * Returns the request, or null if one could not be allocated
+ */
+static struct usb_request *
+tegra_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
+{
+ struct tegra_req *req = NULL;
+
+ req = kzalloc(sizeof *req, gfp_flags);
+ if (!req)
+ return NULL;
+
+ req->req.dma = DMA_ADDR_INVALID;
+ INIT_LIST_HEAD(&req->queue);
+
+ return &req->req;
+}
+
+static void tegra_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct tegra_req *req = NULL;
+
+ req = container_of(_req, struct tegra_req, req);
+
+ if (_req)
+ kfree(req);
+}
+
+static void tegra_queue_td(struct tegra_ep *ep, struct tegra_req *req)
+{
+ int i = ep_index(ep) * 2 + ep_is_in(ep);
+ u32 temp, bitmask, tmp_stat;
+ struct ep_queue_head *dQH = &ep->udc->ep_qh[i];
+ struct tegra_udc *udc = ep->udc;
+
+ bitmask = ep_is_in(ep)
+ ? (1 << (ep_index(ep) + 16))
+ : (1 << (ep_index(ep)));
+
+ /* Flush all the dTD structs out to memory */
+ wmb();
+
+ /* check if the pipe is empty */
+ if (!(list_empty(&ep->queue))) {
+ /* Add td to the end */
+ struct tegra_req *lastreq;
+ lastreq = list_entry(ep->queue.prev, struct tegra_req, queue);
+ lastreq->tail->next_td_ptr =
+ cpu_to_le32(req->head->td_dma & DTD_ADDR_MASK);
+ wmb();
+ /* Read prime bit, if 1 goto done */
+ if (udc_readl(udc, EP_PRIME_REG_OFFSET) & bitmask)
+ goto out;
+
+ do {
+ /* Set ATDTW bit in USBCMD */
+ temp = udc_readl(udc, USB_CMD_REG_OFFSET);
+ temp |= USB_CMD_ATDTW;
+ udc_writel(udc, temp, USB_CMD_REG_OFFSET);
+
+ /* Read correct status bit */
+ tmp_stat = udc_readl(udc, EP_STATUS_REG_OFFSET)
+ & bitmask;
+
+ } while (!(udc_readl(udc, USB_CMD_REG_OFFSET) & USB_CMD_ATDTW));
+
+ /* Write ATDTW bit to 0 */
+ temp = udc_readl(udc, USB_CMD_REG_OFFSET);
+ udc_writel(udc, temp & ~USB_CMD_ATDTW, USB_CMD_REG_OFFSET);
+
+ if (tmp_stat)
+ goto out;
+ }
+
+ /* Write dQH next pointer and terminate bit to 0 */
+ temp = req->head->td_dma & EP_QUEUE_HEAD_NEXT_POINTER_MASK;
+ dQH->next_dtd_ptr = cpu_to_le32(temp);
+
+ /* Clear active and halt bit */
+ temp = cpu_to_le32(~(EP_QUEUE_HEAD_STATUS_ACTIVE
+ | EP_QUEUE_HEAD_STATUS_HALT));
+ dQH->size_ioc_int_sts &= temp;
+
+ tegra_usb_phy_memory_prefetch_on(udc->phy);
+
+ /* Ensure that updates to the QH will occur before priming. */
+ wmb();
+
+ /* Prime endpoint by writing 1 to ENDPTPRIME */
+ temp = ep_is_in(ep)
+ ? (1 << (ep_index(ep) + 16))
+ : (1 << (ep_index(ep)));
+ udc_writel(udc, temp, EP_PRIME_REG_OFFSET);
+out:
+ return;
+}
+
+/**
+ * Fill in the dTD structure
+ * @req : request that the transfer belongs to
+ * @length : return actually data length of the dTD
+ * @dma : return dma address of the dTD
+ * @is_last : return flag if it is the last dTD of the request
+ * return : pointer to the built dTD
+ */
+static struct ep_td_struct *tegra_build_dtd(struct tegra_req *req,
+ unsigned *length, dma_addr_t *dma, int *is_last, gfp_t gfp_flags)
+{
+ u32 swap_temp;
+ struct ep_td_struct *dtd;
+
+ /* how big will this transfer be? */
+ *length = min(req->req.length - req->req.actual,
+ (unsigned)EP_MAX_LENGTH_TRANSFER);
+
+ dtd = dma_pool_alloc(the_udc->td_pool, gfp_flags, dma);
+ if (dtd == NULL)
+ return dtd;
+
+ dtd->td_dma = *dma;
+ /* Clear reserved field */
+ swap_temp = cpu_to_le32(dtd->size_ioc_sts);
+ swap_temp &= ~DTD_RESERVED_FIELDS;
+ dtd->size_ioc_sts = cpu_to_le32(swap_temp);
+
+ /* Init all of buffer page pointers */
+ swap_temp = (u32) (req->req.dma + req->req.actual);
+ dtd->buff_ptr0 = cpu_to_le32(swap_temp);
+ dtd->buff_ptr1 = cpu_to_le32(swap_temp + 0x1000);
+ dtd->buff_ptr2 = cpu_to_le32(swap_temp + 0x2000);
+ dtd->buff_ptr3 = cpu_to_le32(swap_temp + 0x3000);
+ dtd->buff_ptr4 = cpu_to_le32(swap_temp + 0x4000);
+
+ req->req.actual += *length;
+
+ /* zlp is needed if req->req.zero is set */
+ if (req->req.zero) {
+ if (*length == 0 || (*length % req->ep->ep.maxpacket) != 0)
+ *is_last = 1;
+ else
+ *is_last = 0;
+ } else if (req->req.length == req->req.actual)
+ *is_last = 1;
+ else
+ *is_last = 0;
+
+ if ((*is_last) == 0)
+ VDBG("multi-dtd request!");
+
+ /* Fill in the transfer size; set active bit */
+ swap_temp = ((*length << DTD_LENGTH_BIT_POS) | DTD_STATUS_ACTIVE);
+
+ /* Enable interrupt for the last dtd of a request */
+ if (*is_last && !req->req.no_interrupt)
+ swap_temp |= DTD_IOC;
+
+ dtd->size_ioc_sts = cpu_to_le32(swap_temp);
+
+ mb();
+
+ VDBG("length = %d address= 0x%x", *length, (int)*dma);
+
+ return dtd;
+}
+
+/* Generate dtd chain for a request */
+static int tegra_req_to_dtd(struct tegra_req *req, gfp_t gfp_flags)
+{
+ unsigned count;
+ int is_last;
+ int is_first = 1;
+ struct ep_td_struct *last_dtd = NULL, *dtd;
+ dma_addr_t dma;
+
+ tegra_usb_phy_memory_prefetch_off(the_udc->phy);
+
+ do {
+ dtd = tegra_build_dtd(req, &count, &dma, &is_last, gfp_flags);
+ if (dtd == NULL)
+ return -ENOMEM;
+
+ if (is_first) {
+ is_first = 0;
+ req->head = dtd;
+ } else {
+ last_dtd->next_td_ptr = cpu_to_le32(dma);
+ last_dtd->next_td_virt = dtd;
+ }
+ last_dtd = dtd;
+
+ req->dtd_count++;
+ } while (!is_last);
+
+ dtd->next_td_ptr = cpu_to_le32(DTD_NEXT_TERMINATE);
+
+ req->tail = dtd;
+
+ return 0;
+}
+
+/* queues (submits) an I/O request to an endpoint */
+static int
+tegra_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+{
+ struct tegra_ep *ep = container_of(_ep, struct tegra_ep, ep);
+ struct tegra_req *req = container_of(_req, struct tegra_req, req);
+ struct tegra_udc *udc = ep->udc;
+ unsigned long flags;
+ enum dma_data_direction dir;
+ int status;
+
+ /* catch various bogus parameters */
+ if (!_req || !req->req.complete || !req->req.buf
+ || !list_empty(&req->queue)) {
+ VDBG("%s, bad params", __func__);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ if (unlikely(!ep->desc)) {
+ VDBG("%s, bad ep", __func__);
+ spin_unlock_irqrestore(&udc->lock, flags);
+ return -EINVAL;
+ }
+
+ if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
+ if (req->req.length > ep->ep.maxpacket) {
+ spin_unlock_irqrestore(&udc->lock, flags);
+ return -EMSGSIZE;
+ }
+ }
+
+#ifdef CONFIG_TEGRA_GADGET_BOOST_CPU_FREQ
+ if (req->req.length >= BOOST_TRIGGER_SIZE) {
+ ep_queue_request_count++;
+ if (ep_queue_request_count && boost_cpufreq_work_flag)
+ schedule_work(&udc->boost_cpufreq_work);
+ }
+#endif
+
+ dir = ep_is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN)
+ return -ESHUTDOWN;
+
+ req->ep = ep;
+
+ /* map virtual address to hardware */
+ if (req->req.dma == DMA_ADDR_INVALID) {
+ req->req.dma = dma_map_single(udc->gadget.dev.parent,
+ req->req.buf, req->req.length, dir);
+ req->mapped = 1;
+ } else {
+ dma_sync_single_for_device(udc->gadget.dev.parent,
+ req->req.dma, req->req.length, dir);
+ req->mapped = 0;
+ }
+
+ req->req.status = -EINPROGRESS;
+ req->req.actual = 0;
+ req->dtd_count = 0;
+
+
+ /* build dtds and push them to device queue */
+ status = tegra_req_to_dtd(req, gfp_flags);
+ if (status)
+ goto err_unmap;
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ /* re-check if the ep has not been disabled */
+ if (unlikely(!ep->desc)) {
+ spin_unlock_irqrestore(&udc->lock, flags);
+ status = -EINVAL;
+ goto err_unmap;
+ }
+
+ tegra_queue_td(ep, req);
+
+ /* Update ep0 state */
+ if ((ep_index(ep) == 0))
+ udc->ep0_state = DATA_STATE_XMIT;
+
+ /* irq handler advances the queue */
+ if (req != NULL)
+ list_add_tail(&req->queue, &ep->queue);
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return 0;
+
+err_unmap:
+ if (req->mapped) {
+ dma_unmap_single(udc->gadget.dev.parent,
+ req->req.dma, req->req.length, dir);
+ req->req.dma = DMA_ADDR_INVALID;
+ req->mapped = 0;
+ }
+ return status;
+}
+
+/* dequeues (cancels, unlinks) an I/O request from an endpoint */
+static int tegra_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct tegra_ep *ep = container_of(_ep, struct tegra_ep, ep);
+ struct tegra_req *req;
+ struct tegra_udc *udc = ep->udc;
+ unsigned long flags;
+ int ep_num, stopped, ret = 0;
+ u32 epctrl;
+
+ if (!_ep || !_req)
+ return -EINVAL;
+
+ spin_lock_irqsave(&ep->udc->lock, flags);
+ stopped = ep->stopped;
+
+ /* Stop the ep before we deal with the queue */
+ ep->stopped = 1;
+ ep_num = ep_index(ep);
+
+ /* Touch the registers if cable is connected and phy is on */
+ if (vbus_enabled(udc)) {
+ epctrl = udc_readl(udc, EP_CONTROL_REG_OFFSET + (ep_num * 4));
+ if (ep_is_in(ep))
+ epctrl &= ~EPCTRL_TX_ENABLE;
+ else
+ epctrl &= ~EPCTRL_RX_ENABLE;
+ udc_writel(udc, epctrl, EP_CONTROL_REG_OFFSET + (ep_num * 4));
+ }
+
+ /* make sure it's actually queued on this endpoint */
+ list_for_each_entry(req, &ep->queue, queue) {
+ if (&req->req == _req)
+ break;
+ }
+ if (&req->req != _req) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* The request is in progress, or completed but not dequeued */
+ if (ep->queue.next == &req->queue) {
+ _req->status = -ECONNRESET;
+ tegra_ep_fifo_flush(_ep); /* flush current transfer */
+
+ /* The request isn't the last request in this ep queue */
+ if (req->queue.next != &ep->queue) {
+ struct ep_queue_head *qh;
+ struct tegra_req *next_req;
+
+ qh = ep->qh;
+ next_req = list_entry(req->queue.next, struct tegra_req,
+ queue);
+
+ /* Point the QH to the first TD of next request */
+ writel((u32) next_req->head, &qh->curr_dtd_ptr);
+ }
+
+ /* The request hasn't been processed, patch up the TD chain */
+ } else {
+ struct tegra_req *prev_req;
+
+ prev_req = list_entry(req->queue.prev, struct tegra_req, queue);
+ writel(readl(&req->tail->next_td_ptr),
+ &prev_req->tail->next_td_ptr);
+ }
+
+ done(ep, req, -ECONNRESET);
+
+ /* Enable EP */
+out:
+ /* Touch the registers if cable is connected and phy is on */
+ if (vbus_enabled(udc)) {
+ epctrl = udc_readl(udc, EP_CONTROL_REG_OFFSET + (ep_num * 4));
+ if (ep_is_in(ep))
+ epctrl |= EPCTRL_TX_ENABLE;
+ else
+ epctrl |= EPCTRL_RX_ENABLE;
+ udc_writel(udc, epctrl, EP_CONTROL_REG_OFFSET + (ep_num * 4));
+ }
+ ep->stopped = stopped;
+
+ spin_unlock_irqrestore(&ep->udc->lock, flags);
+ return ret;
+}
+
+/**
+ * modify the endpoint halt feature
+ * @ep: the non-isochronous endpoint being stalled
+ * @value: 1--set halt 0--clear halt
+ * Returns zero, or a negative error code.
+ */
+static int tegra_ep_set_halt(struct usb_ep *_ep, int value)
+{
+ struct tegra_ep *ep = NULL;
+ unsigned long flags = 0;
+ int status = -EOPNOTSUPP; /* operation not supported */
+ unsigned char ep_dir = 0, ep_num = 0;
+ struct tegra_udc *udc = NULL;
+
+ ep = container_of(_ep, struct tegra_ep, ep);
+ udc = ep->udc;
+ if (!_ep || !ep->desc) {
+ status = -EINVAL;
+ goto out;
+ }
+
+ if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
+ status = -EOPNOTSUPP;
+ goto out;
+ }
+
+ /* Attempt to halt IN ep will fail if any transfer requests
+ * are still queue */
+ if (value && ep_is_in(ep) && !list_empty(&ep->queue)) {
+ status = -EAGAIN;
+ goto out;
+ }
+
+ status = 0;
+ ep_dir = ep_is_in(ep) ? USB_SEND : USB_RECV;
+ ep_num = (unsigned char)(ep_index(ep));
+ spin_lock_irqsave(&ep->udc->lock, flags);
+ dr_ep_change_stall(udc, ep_num, ep_dir, value);
+ spin_unlock_irqrestore(&ep->udc->lock, flags);
+
+ if (ep_index(ep) == 0) {
+ udc->ep0_state = WAIT_FOR_SETUP;
+ udc->ep0_dir = 0;
+ }
+out:
+ VDBG(" %s %s halt stat %d", ep->ep.name,
+ value ? "set" : "clear", status);
+
+ return status;
+}
+
+static int tegra_ep_fifo_status(struct usb_ep *_ep)
+{
+ struct tegra_ep *ep;
+ struct tegra_udc *udc;
+ int size = 0;
+ u32 bitmask;
+ struct ep_queue_head *d_qh;
+
+ ep = container_of(_ep, struct tegra_ep, ep);
+ if (!_ep || (!ep->desc && ep_index(ep) != 0))
+ return -ENODEV;
+
+ udc = (struct tegra_udc *)ep->udc;
+
+ if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN)
+ return -ESHUTDOWN;
+
+ d_qh = &ep->udc->ep_qh[ep_index(ep) * 2 + ep_is_in(ep)];
+
+ bitmask = (ep_is_in(ep)) ? (1 << (ep_index(ep) + 16)) :
+ (1 << (ep_index(ep)));
+
+ if (udc_readl(udc, EP_STATUS_REG_OFFSET) & bitmask)
+ size = (d_qh->size_ioc_int_sts & DTD_PACKET_SIZE)
+ >> DTD_LENGTH_BIT_POS;
+
+ pr_debug("%s %u\n", __func__, size);
+ return size;
+}
+
+static void tegra_ep_fifo_flush(struct usb_ep *_ep)
+{
+ struct tegra_ep *ep;
+ struct tegra_udc *udc;
+ int ep_num, ep_dir;
+ u32 bits;
+ unsigned long timeout;
+
+ if (!_ep) {
+ return;
+ } else {
+ ep = container_of(_ep, struct tegra_ep, ep);
+ if (!ep->desc)
+ return;
+ }
+ ep_num = ep_index(ep);
+ ep_dir = ep_is_in(ep) ? USB_SEND : USB_RECV;
+ udc = ep->udc;
+
+ if (ep_num == 0)
+ bits = (1 << 16) | 1;
+ else if (ep_dir == USB_SEND)
+ bits = 1 << (16 + ep_num);
+ else
+ bits = 1 << ep_num;
+
+ /* Touch the registers if cable is connected and phy is on */
+ if (!vbus_enabled(udc))
+ return;
+
+ timeout = jiffies + UDC_FLUSH_TIMEOUT_MS;
+ do {
+ udc_writel(udc, bits, EPFLUSH_REG_OFFSET);
+
+ /* Wait until flush complete */
+ while (udc_readl(udc, EPFLUSH_REG_OFFSET)) {
+ if (time_after(jiffies, timeout)) {
+ ERR("ep flush timeout\n");
+ return;
+ }
+ cpu_relax();
+ }
+ /* See if we need to flush again */
+ } while (udc_readl(udc, EP_STATUS_REG_OFFSET) & bits);
+}
+
+static struct usb_ep_ops tegra_ep_ops = {
+ .enable = tegra_ep_enable,
+ .disable = tegra_ep_disable,
+
+ .alloc_request = tegra_alloc_request,
+ .free_request = tegra_free_request,
+
+ .queue = tegra_ep_queue,
+ .dequeue = tegra_ep_dequeue,
+
+ .set_halt = tegra_ep_set_halt,
+ .fifo_status = tegra_ep_fifo_status,
+ .fifo_flush = tegra_ep_fifo_flush, /* flush fifo */
+};
+
+/* Get the current frame number (from DR frame_index Reg ) */
+static int tegra_get_frame(struct usb_gadget *gadget)
+{
+ struct tegra_udc *udc = container_of(gadget, struct tegra_udc, gadget);
+ return (int)(udc_readl(udc, USB_FRINDEX_REG_OFFSET)
+ & USB_FRINDEX_MASKS);
+}
+
+#ifndef CONFIG_USB_ANDROID
+/* Tries to wake up the host connected to this gadget */
+static int tegra_wakeup(struct usb_gadget *gadget)
+{
+ struct tegra_udc *udc = container_of(gadget, struct tegra_udc, gadget);
+ u32 portsc;
+
+ /* Remote wakeup feature not enabled by host */
+ if (!udc->remote_wakeup)
+ return -ENOTSUPP;
+
+ portsc = udc_readl(udc, PORTSCX_REG_OFFSET);
+ /* not suspended? */
+ if (!(portsc & PORTSCX_PORT_SUSPEND))
+ return 0;
+
+ /* trigger force resume */
+ portsc |= PORTSCX_PORT_FORCE_RESUME;
+ udc_writel(udc, portsc, PORTSCX_REG_OFFSET);
+ return 0;
+}
+#endif
+
+static int tegra_set_selfpowered(struct usb_gadget *gadget, int is_on)
+{
+ struct tegra_udc *udc;
+ udc = container_of(gadget, struct tegra_udc, gadget);
+ udc->selfpowered = (is_on != 0);
+ return 0;
+}
+
+/**
+ * Notify controller that VBUS is powered, called by whatever
+ * detects VBUS sessions
+ */
+static int tegra_vbus_session(struct usb_gadget *gadget, int is_active)
+{
+ struct tegra_udc *udc = container_of(gadget, struct tegra_udc, gadget);
+ unsigned long flags;
+ DBG("%s(%d) turn VBUS state from %s to %s", __func__, __LINE__,
+ udc->vbus_active ? "on" : "off", is_active ? "on" : "off");
+
+ if (udc->vbus_active && !is_active) {
+ /* If cable disconnected, cancel any delayed work */
+ cancel_delayed_work(&udc->work);
+ spin_lock_irqsave(&udc->lock, flags);
+ /* reset all internal Queues and inform client driver */
+ reset_queues(udc);
+ /* stop the controller and turn off the clocks */
+ dr_controller_stop(udc);
+ dr_controller_reset(udc);
+ udc->vbus_active = 0;
+ udc->usb_state = USB_STATE_DEFAULT;
+ spin_unlock_irqrestore(&udc->lock,flags);
+ tegra_usb_phy_power_off(udc->phy);
+ if (udc->vbus_reg) {
+ /* set the current limit to 0mA */
+ regulator_set_current_limit(
+ udc->vbus_reg, 0, 0);
+ }
+ } else if (!udc->vbus_active && is_active) {
+ tegra_usb_phy_power_on(udc->phy);
+ /* setup the controller in the device mode */
+ dr_controller_setup(udc);
+ /* setup EP0 for setup packet */
+ ep0_setup(udc);
+ /* initialize the USB and EP states */
+ udc->usb_state = USB_STATE_ATTACHED;
+ udc->ep0_state = WAIT_FOR_SETUP;
+ udc->ep0_dir = 0;
+ udc->vbus_active = 1;
+ /* start the controller */
+ dr_controller_run(udc);
+ if (udc->vbus_reg) {
+ /* set the current limit to 100mA */
+ regulator_set_current_limit(
+ udc->vbus_reg, 0, 100);
+ }
+ /* Schedule work to wait for 1000 msec and check for
+ * charger if setup packet is not received */
+ schedule_delayed_work(&udc->work,
+ USB_CHARGER_DETECTION_WAIT_TIME_MS);
+ }
+ return 0;
+}
+
+/**
+ * Constrain controller's VBUS power usage.
+ * This call is used by gadget drivers during SET_CONFIGURATION calls,
+ * reporting how much power the device may consume. For example, this
+ * could affect how quickly batteries are recharged.
+ *
+ * Returns zero on success, else negative errno.
+ */
+static int tegra_vbus_draw(struct usb_gadget *gadget, unsigned mA)
+{
+ struct tegra_udc *udc;
+
+ udc = container_of(gadget, struct tegra_udc, gadget);
+ /* check udc regulator is available for drawing the vbus current */
+ if (udc->vbus_reg) {
+ udc->current_limit = mA;
+ schedule_work(&udc->charger_work);
+ }
+
+ if (udc->transceiver)
+ return otg_set_power(udc->transceiver, mA);
+ return -ENOTSUPP;
+}
+
+/**
+ * Change Data+ pullup status
+ * this func is used by usb_gadget_connect/disconnect
+ */
+static int tegra_pullup(struct usb_gadget *gadget, int is_on)
+{
+ struct tegra_udc *udc;
+ u32 tmp;
+
+ udc = container_of(gadget, struct tegra_udc, gadget);
+ udc->softconnect = (is_on != 0);
+ if (udc->transceiver && udc->transceiver->state !=
+ OTG_STATE_B_PERIPHERAL)
+ return 0;
+
+ tmp = udc_readl(udc, USB_CMD_REG_OFFSET);
+ if (can_pullup(udc))
+ udc_writel(udc, tmp | USB_CMD_RUN_STOP,
+ USB_CMD_REG_OFFSET);
+ else
+ udc_writel(udc, (tmp & ~USB_CMD_RUN_STOP),
+ USB_CMD_REG_OFFSET);
+
+ return 0;
+}
+
+/* Release udc structures */
+static void tegra_udc_release(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct tegra_udc *udc = platform_get_drvdata(pdev);
+
+ complete(udc->done);
+ tegra_usb_phy_close(udc->phy);
+ kfree(udc);
+}
+
+static int tegra_udc_start(struct usb_gadget_driver *driver,
+ int (*bind)(struct usb_gadget *));
+static int tegra_udc_stop(struct usb_gadget_driver *driver);
+/* defined in gadget.h */
+static struct usb_gadget_ops tegra_gadget_ops = {
+ .get_frame = tegra_get_frame,
+#ifndef CONFIG_USB_ANDROID
+ .wakeup = tegra_wakeup,
+#endif
+ .set_selfpowered = tegra_set_selfpowered,
+ .vbus_session = tegra_vbus_session,
+ .vbus_draw = tegra_vbus_draw,
+ .pullup = tegra_pullup,
+ .start = tegra_udc_start,
+ .stop = tegra_udc_stop,
+};
+
+static int tegra_udc_setup_gadget_dev(struct tegra_udc *udc)
+{
+ /* Setup gadget structure */
+ udc->gadget.ops = &tegra_gadget_ops;
+ udc->gadget.is_dualspeed = 1;
+ udc->gadget.ep0 = &udc->eps[0].ep;
+ INIT_LIST_HEAD(&udc->gadget.ep_list);
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+ udc->gadget.name = driver_name;
+
+ /* Setup gadget.dev and register with kernel */
+ dev_set_name(&udc->gadget.dev, "gadget");
+ udc->gadget.dev.release = tegra_udc_release;
+ udc->gadget.dev.parent = &udc->pdev->dev;
+
+ return device_register(&udc->gadget.dev);
+}
+
+
+/**
+ * Set protocol stall on ep0, protocol stall will automatically be cleared
+ * on new transaction.
+ */
+static void ep0stall(struct tegra_udc *udc)
+{
+ u32 tmp;
+
+ /* must set tx and rx to stall at the same time */
+ tmp = udc_readl(udc, EP_CONTROL_REG_OFFSET);
+ tmp |= EPCTRL_TX_EP_STALL | EPCTRL_RX_EP_STALL;
+ udc_writel(udc, tmp, EP_CONTROL_REG_OFFSET);
+ udc->ep0_state = WAIT_FOR_SETUP;
+ udc->ep0_dir = 0;
+}
+
+/* Prime a status phase for ep0 */
+static int ep0_prime_status(struct tegra_udc *udc, int direction)
+{
+ struct tegra_req *req = udc->status_req;
+ struct tegra_ep *ep;
+
+ if (direction == EP_DIR_IN)
+ udc->ep0_dir = USB_DIR_IN;
+ else
+ udc->ep0_dir = USB_DIR_OUT;
+
+ ep = &udc->eps[0];
+ udc->ep0_state = WAIT_FOR_OUT_STATUS;
+
+ req->ep = ep;
+ req->req.length = 0;
+ req->req.status = -EINPROGRESS;
+ req->req.actual = 0;
+ req->req.complete = NULL;
+ req->dtd_count = 0;
+
+ if (tegra_req_to_dtd(req, GFP_ATOMIC) == 0)
+ tegra_queue_td(ep, req);
+ else
+ return -ENOMEM;
+
+ list_add_tail(&req->queue, &ep->queue);
+
+ return 0;
+}
+
+static void udc_reset_ep_queue(struct tegra_udc *udc, u8 pipe)
+{
+ struct tegra_ep *ep = get_ep_by_pipe(udc, pipe);
+
+ if (ep->name)
+ nuke(ep, -ESHUTDOWN);
+}
+
+/* ch9 Set address */
+static void ch9setaddress(struct tegra_udc *udc, u16 value, u16 index,
+ u16 length)
+{
+ /* Save the new address to device struct */
+ udc->device_address = (u8) value;
+ /* Update usb state */
+ udc->usb_state = USB_STATE_ADDRESS;
+ /* Status phase */
+ if (ep0_prime_status(udc, EP_DIR_IN))
+ ep0stall(udc);
+}
+
+/* ch9 Get status */
+static void ch9getstatus(struct tegra_udc *udc, u8 request_type, u16 value,
+ u16 index, u16 length)
+{
+ u16 tmp = 0; /* Status, cpu endian */
+ struct tegra_req *req;
+ struct tegra_ep *ep;
+
+ ep = &udc->eps[0];
+
+ if ((request_type & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
+ /* Get device status */
+ if (udc->selfpowered)
+ tmp = 1 << USB_DEVICE_SELF_POWERED;
+ tmp |= udc->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP;
+ } else if ((request_type & USB_RECIP_MASK) == USB_RECIP_INTERFACE) {
+ /* Get interface status
+ * We don't have interface information in udc driver */
+ tmp = 0;
+ } else if ((request_type & USB_RECIP_MASK) == USB_RECIP_ENDPOINT) {
+ /* Get endpoint status */
+ struct tegra_ep *target_ep;
+
+ target_ep = get_ep_by_pipe(udc, get_pipe_by_windex(index));
+
+ /* stall if endpoint doesn't exist */
+ if (!target_ep->desc)
+ goto stall;
+ tmp = dr_ep_get_stall(udc, ep_index(target_ep),
+ ep_is_in(target_ep)) << USB_ENDPOINT_HALT;
+ }
+
+ udc->ep0_dir = USB_DIR_IN;
+ /* Borrow the per device status_req */
+ req = udc->status_req;
+ /* Fill in the reqest structure */
+ *((u16 *) req->req.buf) = cpu_to_le16(tmp);
+ req->ep = ep;
+ req->req.length = 2;
+ req->req.status = -EINPROGRESS;
+ req->req.actual = 0;
+ req->req.complete = NULL;
+ req->dtd_count = 0;
+
+ /* map virtual address to hardware */
+ if (req->req.dma == DMA_ADDR_INVALID) {
+ req->req.dma = dma_map_single(ep->udc->gadget.dev.parent,
+ req->req.buf,
+ req->req.length, ep_is_in(ep)
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+ req->mapped = 1;
+ } else {
+ dma_sync_single_for_device(ep->udc->gadget.dev.parent,
+ req->req.dma, req->req.length,
+ ep_is_in(ep)
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+ req->mapped = 0;
+ }
+
+ /* prime the data phase */
+ if ((tegra_req_to_dtd(req, GFP_ATOMIC) == 0))
+ tegra_queue_td(ep, req);
+ else /* no mem */
+ goto stall;
+
+ list_add_tail(&req->queue, &ep->queue);
+ udc->ep0_state = DATA_STATE_XMIT;
+ return;
+stall:
+ ep0stall(udc);
+}
+
+static void udc_test_mode(struct tegra_udc *udc, u32 test_mode)
+{
+ struct tegra_req *req;
+ struct tegra_ep *ep;
+ u32 portsc, bitmask;
+ unsigned long timeout;
+
+ /* Ack the ep0 IN */
+ if (ep0_prime_status(udc, EP_DIR_IN))
+ ep0stall(udc);
+
+ /* get the ep0 */
+ ep = &udc->eps[0];
+ bitmask = ep_is_in(ep)
+ ? (1 << (ep_index(ep) + 16))
+ : (1 << (ep_index(ep)));
+
+ timeout = jiffies + HZ;
+ /* Wait until ep0 IN endpoint txfr is complete */
+ while (!(udc_readl(udc, EP_COMPLETE_REG_OFFSET) & bitmask)) {
+ if (time_after(jiffies, timeout)) {
+ pr_err("Timeout for Ep0 IN Ack\n");
+ break;
+ }
+ cpu_relax();
+ }
+
+ switch (test_mode << PORTSCX_PTC_BIT_POS) {
+ case PORTSCX_PTC_JSTATE:
+ VDBG("TEST_J\n");
+ break;
+ case PORTSCX_PTC_KSTATE:
+ VDBG("TEST_K\n");
+ break;
+ case PORTSCX_PTC_SEQNAK:
+ VDBG("TEST_SE0_NAK\n");
+ break;
+ case PORTSCX_PTC_PACKET:
+ VDBG("TEST_PACKET\n");
+
+ /* get the ep and configure for IN direction */
+ ep = &udc->eps[0];
+ udc->ep0_dir = USB_DIR_IN;
+
+ /* Initialize ep0 status request structure */
+ req = container_of(tegra_alloc_request(NULL, GFP_ATOMIC),
+ struct tegra_req, req);
+ /* allocate a small amount of memory to get valid address */
+ req->req.buf = kmalloc(sizeof(tegra_udc_test_packet),
+ GFP_ATOMIC);
+ req->req.dma = virt_to_phys(req->req.buf);
+
+ /* Fill in the reqest structure */
+ memcpy(req->req.buf, tegra_udc_test_packet,
+ sizeof(tegra_udc_test_packet));
+ req->ep = ep;
+ req->req.length = sizeof(tegra_udc_test_packet);
+ req->req.status = -EINPROGRESS;
+ req->req.actual = 0;
+ req->req.complete = NULL;
+ req->dtd_count = 0;
+ req->mapped = 0;
+
+ dma_sync_single_for_device(ep->udc->gadget.dev.parent,
+ req->req.dma, req->req.length,
+ ep_is_in(ep)
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+
+ /* prime the data phase */
+ if ((tegra_req_to_dtd(req, GFP_ATOMIC) == 0))
+ tegra_queue_td(ep, req);
+ else /* no mem */
+ goto stall;
+
+ list_add_tail(&req->queue, &ep->queue);
+ udc->ep0_state = DATA_STATE_XMIT;
+ break;
+ case PORTSCX_PTC_FORCE_EN:
+ VDBG("TEST_FORCE_EN\n");
+ break;
+ default:
+ ERR("udc unknown test mode[%d]!\n", test_mode);
+ goto stall;
+ }
+
+ /* read the portsc register */
+ portsc = udc_readl(udc, PORTSCX_REG_OFFSET);
+ /* set the test mode selector */
+ portsc |= test_mode << PORTSCX_PTC_BIT_POS;
+ udc_writel(udc, portsc, PORTSCX_REG_OFFSET);
+
+ /*
+ * The device must have its power cycled to exit test mode.
+ * See USB 2.0 spec, section 9.4.9 for test modes operation
+ * in "Set Feature".
+ * See USB 2.0 spec, section 7.1.20 for test modes.
+ */
+ pr_info("udc entering the test mode, power cycle to exit test mode\n");
+ return;
+stall:
+ ep0stall(udc);
+}
+
+static void setup_received_irq(struct tegra_udc *udc,
+ struct usb_ctrlrequest *setup)
+{
+ u16 wValue = le16_to_cpu(setup->wValue);
+ u16 wIndex = le16_to_cpu(setup->wIndex);
+ u16 wLength = le16_to_cpu(setup->wLength);
+
+ udc_reset_ep_queue(udc, 0);
+
+ /* We process some stardard setup requests here */
+ switch (setup->bRequest) {
+ case USB_REQ_GET_STATUS:
+ /* Data+Status phase from udc */
+ if ((setup->bRequestType & (USB_DIR_IN | USB_TYPE_MASK))
+ != (USB_DIR_IN | USB_TYPE_STANDARD))
+ break;
+ ch9getstatus(udc, setup->bRequestType, wValue, wIndex, wLength);
+ return;
+
+ case USB_REQ_SET_ADDRESS:
+ /* Status phase from udc */
+ if (setup->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD
+ | USB_RECIP_DEVICE))
+ break;
+ /* This delay is necessary for some windows drivers to
+ * properly recognize the device */
+ mdelay(1);
+ ch9setaddress(udc, wValue, wIndex, wLength);
+ return;
+
+ case USB_REQ_CLEAR_FEATURE:
+ case USB_REQ_SET_FEATURE:
+ /* Status phase from udc */
+ {
+ int rc = -EOPNOTSUPP;
+
+ if (setup->bRequestType == USB_RECIP_DEVICE &&
+ wValue == USB_DEVICE_TEST_MODE) {
+ /*
+ * If the feature selector is TEST_MODE, then the most
+ * significant byte of wIndex is used to specify the
+ * specific test mode and the lower byte of wIndex must
+ * be zero.
+ */
+ udc_test_mode(udc, wIndex >> 8);
+ return;
+
+ } else if ((setup->bRequestType &
+ (USB_RECIP_MASK | USB_TYPE_MASK)) ==
+ (USB_RECIP_ENDPOINT | USB_TYPE_STANDARD)) {
+ int pipe = get_pipe_by_windex(wIndex);
+ struct tegra_ep *ep;
+
+ if (wValue != 0 || wLength != 0 || pipe > udc->max_ep)
+ break;
+ ep = get_ep_by_pipe(udc, pipe);
+
+ spin_unlock(&udc->lock);
+ rc = tegra_ep_set_halt(&ep->ep,
+ (setup->bRequest == USB_REQ_SET_FEATURE)
+ ? 1 : 0);
+ spin_lock(&udc->lock);
+
+ } else if ((setup->bRequestType & (USB_RECIP_MASK
+ | USB_TYPE_MASK)) == (USB_RECIP_DEVICE
+ | USB_TYPE_STANDARD)) {
+ /* Note: The driver has not include OTG support yet.
+ * This will be set when OTG support is added */
+ if (!gadget_is_otg(&udc->gadget))
+ break;
+ else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE)
+ udc->gadget.b_hnp_enable = 1;
+ else if (setup->bRequest == USB_DEVICE_A_HNP_SUPPORT)
+ udc->gadget.a_hnp_support = 1;
+ else if (setup->bRequest ==
+ USB_DEVICE_A_ALT_HNP_SUPPORT)
+ udc->gadget.a_alt_hnp_support = 1;
+ else
+ break;
+ rc = 0;
+ } else
+ break;
+
+ if (rc == 0) {
+ if (ep0_prime_status(udc, EP_DIR_IN))
+ ep0stall(udc);
+ }
+ return;
+ }
+
+ default:
+ break;
+ }
+
+ /* Requests handled by gadget */
+ if (wLength) {
+ /* Data phase from gadget, status phase from udc */
+ udc->ep0_dir = (setup->bRequestType & USB_DIR_IN)
+ ? USB_DIR_IN : USB_DIR_OUT;
+ spin_unlock(&udc->lock);
+ if (udc->driver && udc->driver->setup(&udc->gadget,
+ &udc->local_setup_buff) < 0)
+ ep0stall(udc);
+ spin_lock(&udc->lock);
+ udc->ep0_state = (setup->bRequestType & USB_DIR_IN)
+ ? DATA_STATE_XMIT : DATA_STATE_RECV;
+ } else {
+ /* No data phase, IN status from gadget */
+ udc->ep0_dir = USB_DIR_IN;
+ spin_unlock(&udc->lock);
+ if (udc->driver && udc->driver->setup(&udc->gadget,
+ &udc->local_setup_buff) < 0)
+ ep0stall(udc);
+ spin_lock(&udc->lock);
+ udc->ep0_state = WAIT_FOR_OUT_STATUS;
+ }
+}
+
+/* Process request for Data or Status phase of ep0
+ * prime status phase if needed */
+static void ep0_req_complete(struct tegra_udc *udc, struct tegra_ep *ep0,
+ struct tegra_req *req)
+{
+ if (udc->usb_state == USB_STATE_ADDRESS) {
+ /* Set the new address */
+ u32 new_address = (u32) udc->device_address;
+ udc_writel(udc, new_address << USB_DEVICE_ADDRESS_BIT_POS,
+ USB_DEVICE_ADDR_REG_OFFSET);
+ }
+
+ done(ep0, req, 0);
+
+ switch (udc->ep0_state) {
+ case DATA_STATE_XMIT:
+ /* receive status phase */
+ if (ep0_prime_status(udc, EP_DIR_OUT))
+ ep0stall(udc);
+ break;
+ case DATA_STATE_RECV:
+ /* send status phase */
+ if (ep0_prime_status(udc, EP_DIR_IN))
+ ep0stall(udc);
+ break;
+ case WAIT_FOR_OUT_STATUS:
+ udc->ep0_state = WAIT_FOR_SETUP;
+ break;
+ case WAIT_FOR_SETUP:
+ ERR("Unexpect ep0 packets\n");
+ break;
+ default:
+ ep0stall(udc);
+ break;
+ }
+}
+
+/* Tripwire mechanism to ensure a setup packet payload is extracted without
+ * being corrupted by another incoming setup packet */
+static void tripwire_handler(struct tegra_udc *udc, u8 ep_num, u8 *buffer_ptr)
+{
+ u32 temp;
+ struct ep_queue_head *qh;
+
+ qh = &udc->ep_qh[ep_num * 2 + EP_DIR_OUT];
+
+ /* Clear bit in ENDPTSETUPSTAT */
+ temp = udc_readl(udc, EP_SETUP_STATUS_REG_OFFSET);
+ udc_writel(udc, temp | (1 << ep_num), EP_SETUP_STATUS_REG_OFFSET);
+
+ /* while a hazard exists when setup package arrives */
+ do {
+ /* Set Setup Tripwire */
+ temp = udc_readl(udc, USB_CMD_REG_OFFSET);
+ udc_writel(udc, temp | USB_CMD_SUTW, USB_CMD_REG_OFFSET);
+
+ /* Copy the setup packet to local buffer */
+ memcpy(buffer_ptr, (u8 *) qh->setup_buffer, 8);
+ } while (!(udc_readl(udc, USB_CMD_REG_OFFSET) & USB_CMD_SUTW));
+
+ /* Clear Setup Tripwire */
+ temp = udc_readl(udc, USB_CMD_REG_OFFSET);
+ udc_writel(udc, temp & ~USB_CMD_SUTW, USB_CMD_REG_OFFSET);
+}
+
+/* process-ep_req(): free the completed Tds for this req */
+static int process_ep_req(struct tegra_udc *udc, int pipe,
+ struct tegra_req *curr_req)
+{
+ struct ep_td_struct *curr_td;
+ int td_complete, actual, remaining_length, j, tmp;
+ int status = 0;
+ int errors = 0;
+ struct ep_queue_head *curr_qh = &udc->ep_qh[pipe];
+ int direction = pipe % 2;
+
+ curr_td = curr_req->head;
+ td_complete = 0;
+ actual = curr_req->req.length;
+
+ for (j = 0; j < curr_req->dtd_count; j++) {
+ /* Fence read for coherency of AHB master intiated writes */
+ readb(IO_ADDRESS(IO_PPCS_PHYS + USB1_PREFETCH_ID));
+
+ dma_sync_single_for_cpu(udc->gadget.dev.parent, curr_td->td_dma,
+ sizeof(struct ep_td_struct), DMA_FROM_DEVICE);
+
+ remaining_length = (le32_to_cpu(curr_td->size_ioc_sts)
+ & DTD_PACKET_SIZE)
+ >> DTD_LENGTH_BIT_POS;
+ actual -= remaining_length;
+ errors = le32_to_cpu(curr_td->size_ioc_sts);
+ if (errors & DTD_ERROR_MASK) {
+ if (errors & DTD_STATUS_HALTED) {
+ ERR("dTD error %08x QH=%d\n", errors, pipe);
+ /* Clear the errors and Halt condition */
+ tmp = le32_to_cpu(curr_qh->size_ioc_int_sts);
+ tmp &= ~errors;
+ curr_qh->size_ioc_int_sts = cpu_to_le32(tmp);
+ status = -EPIPE;
+ /* FIXME: continue with next queued TD? */
+
+ break;
+ }
+ if (errors & DTD_STATUS_DATA_BUFF_ERR) {
+ VDBG("Transfer overflow");
+ status = -EPROTO;
+ break;
+ } else if (errors & DTD_STATUS_TRANSACTION_ERR) {
+ VDBG("ISO error");
+ status = -EILSEQ;
+ break;
+ } else
+ ERR("Unknown error has occurred (0x%x)!\n",
+ errors);
+
+ } else if (le32_to_cpu(curr_td->size_ioc_sts)
+ & DTD_STATUS_ACTIVE) {
+ VDBG("Request not complete");
+ status = REQ_UNCOMPLETE;
+ return status;
+ } else if (remaining_length) {
+ if (direction) {
+ VDBG("Transmit dTD remaining length not zero");
+ status = -EPROTO;
+ break;
+ } else {
+ td_complete++;
+ break;
+ }
+ } else {
+ td_complete++;
+ VDBG("dTD transmitted successful");
+ }
+
+ if (j != curr_req->dtd_count - 1)
+ curr_td = (struct ep_td_struct *)curr_td->next_td_virt;
+ }
+
+ if (status)
+ return status;
+
+ curr_req->req.actual = actual;
+
+ return 0;
+}
+
+/* Process a DTD completion interrupt */
+static void dtd_complete_irq(struct tegra_udc *udc)
+{
+ u32 bit_pos;
+ int i, ep_num, direction, bit_mask, status;
+ struct tegra_ep *curr_ep;
+ struct tegra_req *curr_req, *temp_req;
+
+ /* Clear the bits in the register */
+ bit_pos = udc_readl(udc, EP_COMPLETE_REG_OFFSET);
+ udc_writel(udc, bit_pos, EP_COMPLETE_REG_OFFSET);
+
+ if (!bit_pos)
+ return;
+
+ for (i = 0; i < udc->max_ep; i++) {
+ ep_num = i >> 1;
+ direction = i % 2;
+
+ bit_mask = 1 << (ep_num + 16 * direction);
+
+ if (!(bit_pos & bit_mask))
+ continue;
+
+ curr_ep = get_ep_by_pipe(udc, i);
+
+ /* If the ep is configured */
+ if (curr_ep->name == NULL) {
+ WARNING("Invalid EP?");
+ continue;
+ }
+
+ /* process the req queue until an uncomplete request */
+ list_for_each_entry_safe(curr_req, temp_req, &curr_ep->queue,
+ queue) {
+ status = process_ep_req(udc, i, curr_req);
+
+ VDBG("status of process_ep_req= %d, ep = %d",
+ status, ep_num);
+ if (status == REQ_UNCOMPLETE)
+ break;
+ /* write back status to req */
+ curr_req->req.status = status;
+
+ if (ep_num == 0) {
+ ep0_req_complete(udc, curr_ep, curr_req);
+ break;
+ } else
+ done(curr_ep, curr_req, status);
+ }
+ }
+}
+
+/* Process a port change interrupt */
+static void port_change_irq(struct tegra_udc *udc)
+{
+ u32 speed;
+ unsigned int port_control_reg_offset;
+
+ if (udc->has_hostpc)
+ port_control_reg_offset = USB_HOSTPCX_DEVLC_REG_OFFSET;
+ else
+ port_control_reg_offset = PORTSCX_REG_OFFSET;
+
+ /* Bus resetting is finished */
+ if (!(udc_readl(udc, port_control_reg_offset) & PORTSCX_PORT_RESET)) {
+ /* Get the speed */
+ speed = (udc_readl(udc, port_control_reg_offset)
+ & PORTSCX_PORT_SPEED_MASK);
+ if (speed == PORTSCX_PORT_SPEED_HIGH)
+ udc->gadget.speed = USB_SPEED_HIGH;
+ else if (speed == PORTSCX_PORT_SPEED_FULL)
+ udc->gadget.speed = USB_SPEED_FULL;
+ else if (speed == PORTSCX_PORT_SPEED_LOW)
+ udc->gadget.speed = USB_SPEED_LOW;
+ else
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+ }
+
+ /* Update USB state */
+ if (!udc->resume_state)
+ udc->usb_state = USB_STATE_DEFAULT;
+}
+
+/* Process suspend interrupt */
+static void suspend_irq(struct tegra_udc *udc)
+{
+ udc->resume_state = udc->usb_state;
+ udc->usb_state = USB_STATE_SUSPENDED;
+
+ /* report suspend to the driver, serial.c does not support this */
+ if (udc->driver && udc->driver->suspend)
+ udc->driver->suspend(&udc->gadget);
+}
+
+static void bus_resume(struct tegra_udc *udc)
+{
+ udc->usb_state = udc->resume_state;
+ udc->resume_state = 0;
+
+ /* report resume to the driver, serial.c does not support this */
+ if (udc->driver && udc->driver->resume)
+ udc->driver->resume(&udc->gadget);
+}
+
+/* Clear up all ep queues */
+static int reset_queues(struct tegra_udc *udc)
+{
+ u8 pipe;
+
+ for (pipe = 0; pipe < udc->max_pipes; pipe++)
+ udc_reset_ep_queue(udc, pipe);
+
+ /* report disconnect; the driver is already quiesced */
+ spin_unlock(&udc->lock);
+ if (udc->driver && udc->driver->disconnect)
+ udc->driver->disconnect(&udc->gadget);
+ spin_lock(&udc->lock);
+
+ return 0;
+}
+
+/* Process reset interrupt */
+static void reset_irq(struct tegra_udc *udc)
+{
+ u32 temp;
+ unsigned long timeout;
+
+ /* Clear the device address */
+ temp = udc_readl(udc, USB_DEVICE_ADDR_REG_OFFSET);
+ udc_writel(udc, temp & ~USB_DEVICE_ADDRESS_MASK,
+ USB_DEVICE_ADDR_REG_OFFSET);
+
+ udc->device_address = 0;
+
+ /* Clear usb state */
+ udc->resume_state = 0;
+ udc->ep0_dir = 0;
+ udc->ep0_state = WAIT_FOR_SETUP;
+ udc->remote_wakeup = 0; /* default to 0 on reset */
+ udc->gadget.b_hnp_enable = 0;
+ udc->gadget.a_hnp_support = 0;
+ udc->gadget.a_alt_hnp_support = 0;
+
+ /* Clear all the setup token semaphores */
+ temp = udc_readl(udc, EP_SETUP_STATUS_REG_OFFSET);
+ udc_writel(udc, temp, EP_SETUP_STATUS_REG_OFFSET);
+
+ /* Clear all the endpoint complete status bits */
+ temp = udc_readl(udc, EP_COMPLETE_REG_OFFSET);
+ udc_writel(udc, temp, EP_COMPLETE_REG_OFFSET);
+
+ timeout = jiffies + 100;
+ while (udc_readl(udc, EP_PRIME_REG_OFFSET)) {
+ /* Wait until all endptprime bits cleared */
+ if (time_after(jiffies, timeout)) {
+ ERR("Timeout for reset\n");
+ break;
+ }
+ cpu_relax();
+ }
+
+ /* Write 1s to the flush register */
+ udc_writel(udc, 0xffffffff, EPFLUSH_REG_OFFSET);
+
+ /* When the bus reset is seen on Tegra, the PORTSCX_PORT_RESET bit
+ * is not set. Reset all the queues, include XD, dTD, EP queue
+ * head and TR Queue */
+ VDBG("Bus reset");
+ reset_queues(udc);
+ udc->usb_state = USB_STATE_DEFAULT;
+}
+
+static void tegra_udc_set_current_limit_work(struct work_struct *work)
+{
+ struct tegra_udc *udc = container_of(work, struct tegra_udc,
+ charger_work);
+ /* check udc regulator is available for drawing vbus current*/
+ if (udc->vbus_reg) {
+ /* set the current limit in uA */
+ regulator_set_current_limit(
+ udc->vbus_reg, 0,
+ udc->current_limit * 1000);
+ }
+}
+
+#ifdef CONFIG_TEGRA_GADGET_BOOST_CPU_FREQ
+static void tegra_udc_boost_cpu_frequency_work(struct work_struct *work)
+{
+ if (ep_queue_request_count && boost_cpufreq_work_flag) {
+ pm_qos_update_request(&boost_cpu_freq_req,
+ (s32)CONFIG_TEGRA_GADGET_BOOST_CPU_FREQ * 1000);
+ boost_cpufreq_work_flag = 0;
+ } else if (!ep_queue_request_count && !boost_cpufreq_work_flag) {
+ pm_qos_update_request(&boost_cpu_freq_req,
+ PM_QOS_DEFAULT_VALUE);
+ boost_cpufreq_work_flag = 1;
+ }
+}
+#endif
+
+static void tegra_udc_irq_work(struct work_struct *irq_work)
+{
+ struct tegra_udc *udc = container_of(irq_work, struct tegra_udc,
+ irq_work);
+ DBG("%s(%d) BEGIN\n", __func__, __LINE__);
+
+ /* Check whether cable is connected*/
+ if (vbus_enabled(udc))
+ tegra_vbus_session(&udc->gadget, 1);
+ else
+ tegra_vbus_session(&udc->gadget, 0);
+
+ DBG("%s(%d) END\n", __func__, __LINE__);
+}
+
+/**
+ * If VBUS is detected and setup packet is not received in 100ms then
+ * work thread starts and checks for the USB charger detection.
+ */
+static void tegra_udc_charger_detect_work(struct work_struct *work)
+{
+ struct tegra_udc *udc = container_of(work, struct tegra_udc, work.work);
+ DBG("%s(%d) BEGIN\n", __func__, __LINE__);
+
+ /* check for the platform charger detection */
+ if (tegra_usb_phy_charger_detected(udc->phy)) {
+ printk(KERN_INFO "USB compliant charger detected\n");
+ /* check udc regulator is available for drawing vbus current*/
+ if (udc->vbus_reg) {
+ /* set the current limit in uA */
+ regulator_set_current_limit(
+ udc->vbus_reg, 0,
+ USB_CHARGING_CURRENT_LIMIT_MA*1000);
+ }
+ }
+
+ DBG("%s(%d) END\n", __func__, __LINE__);
+}
+
+/* Restart device controller in the OTG mode on VBUS detection */
+static void tegra_udc_restart(struct tegra_udc *udc)
+{
+ DBG("%s(%d) BEGIN\n", __func__, __LINE__);
+
+ /* setup the controller in the device mode */
+ dr_controller_setup(udc);
+ /* setup EP0 for setup packet */
+ ep0_setup(udc);
+ udc->vbus_active = 1;
+ /* start the controller */
+ dr_controller_run(udc);
+ /* initialize the USB and EP states */
+ udc->usb_state = USB_STATE_ATTACHED;
+ udc->ep0_state = WAIT_FOR_SETUP;
+ udc->ep0_dir = 0;
+
+ DBG("%s(%d) END\n", __func__, __LINE__);
+}
+
+/* USB device controller interrupt handler */
+static irqreturn_t tegra_udc_irq(int irq, void *_udc)
+{
+ struct tegra_udc *udc = _udc;
+ u32 irq_src, temp;
+ irqreturn_t status = IRQ_NONE;
+ unsigned long flags;
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ if (!udc->transceiver) {
+ temp = udc_readl(udc, VBUS_WAKEUP_REG_OFFSET);
+ /* write back the register to clear the interrupt */
+ udc_writel(udc, temp, VBUS_WAKEUP_REG_OFFSET);
+ if (temp & USB_SYS_VBUS_WAKEUP_INT_STATUS)
+ schedule_work(&udc->irq_work);
+ status = IRQ_HANDLED;
+ }
+
+ /* Disable ISR for OTG host mode */
+ if (udc->stopped) {
+ spin_unlock_irqrestore(&udc->lock, flags);
+ return status;
+ }
+
+ /* Fence read for coherency of AHB master intiated writes */
+ readb(IO_ADDRESS(IO_PPCS_PHYS + USB1_PREFETCH_ID));
+
+ irq_src = udc_readl(udc, USB_STS_REG_OFFSET) &
+ udc_readl(udc, USB_INTR_REG_OFFSET);
+
+ /* Clear notification bits */
+ udc_writel(udc, irq_src, USB_STS_REG_OFFSET);
+
+ /* Need to resume? */
+ if (udc->usb_state == USB_STATE_SUSPENDED)
+ if (!(udc_readl(udc, PORTSCX_REG_OFFSET)
+ & PORTSCX_PORT_SUSPEND))
+ bus_resume(udc);
+
+ /* USB Interrupt */
+ if (irq_src & USB_STS_INT) {
+ VDBG("Packet int");
+ /* Setup package, we only support ep0 as control ep */
+ if (udc_readl(udc, EP_SETUP_STATUS_REG_OFFSET) &
+ EP_SETUP_STATUS_EP0) {
+ /* Setup packet received, we are connected to host
+ * and not to charger. Cancel any delayed work */
+ __cancel_delayed_work(&udc->work);
+ tripwire_handler(udc, 0,
+ (u8 *) (&udc->local_setup_buff));
+ setup_received_irq(udc, &udc->local_setup_buff);
+ status = IRQ_HANDLED;
+ }
+
+ /* completion of dtd */
+ if (udc_readl(udc, EP_COMPLETE_REG_OFFSET)) {
+ dtd_complete_irq(udc);
+ status = IRQ_HANDLED;
+ }
+ }
+
+ /* SOF (for ISO transfer) */
+ if (irq_src & USB_STS_SOF)
+ status = IRQ_HANDLED;
+
+ /* Port Change */
+ if (irq_src & USB_STS_PORT_CHANGE) {
+ port_change_irq(udc);
+ status = IRQ_HANDLED;
+ }
+
+ /* Reset Received */
+ if (irq_src & USB_STS_RESET) {
+ reset_irq(udc);
+ status = IRQ_HANDLED;
+ }
+
+ /* Sleep Enable (Suspend) */
+ if (irq_src & USB_STS_SUSPEND) {
+ suspend_irq(udc);
+ status = IRQ_HANDLED;
+ }
+
+ if (irq_src & (USB_STS_ERR | USB_STS_SYS_ERR))
+ VDBG("Error IRQ %x", irq_src);
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+ return status;
+}
+
+/**
+ * Hook to gadget drivers
+ * Called by initialization code of gadget drivers
+ */
+static int tegra_udc_start(struct usb_gadget_driver *driver,
+ int (*bind)(struct usb_gadget *))
+{
+ struct tegra_udc *udc = the_udc;
+ int retval = -ENODEV;
+ unsigned long flags = 0;
+ DBG("%s(%d) BEGIN\n", __func__, __LINE__);
+
+ if (!udc)
+ return -ENODEV;
+
+ if (!driver || (driver->speed != USB_SPEED_FULL
+ && driver->speed != USB_SPEED_HIGH)
+ || !bind || !driver->disconnect
+ || !driver->setup)
+ return -EINVAL;
+
+ if (udc->driver)
+ return -EBUSY;
+
+ /* lock is needed but whether should use this lock or another */
+ spin_lock_irqsave(&udc->lock, flags);
+
+ driver->driver.bus = NULL;
+ /* hook up the driver */
+ udc->driver = driver;
+ udc->gadget.dev.driver = &driver->driver;
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ /* bind udc driver to gadget driver */
+ retval = bind(&udc->gadget);
+ if (retval) {
+ VDBG("bind to %s --> %d", driver->driver.name, retval);
+ udc->gadget.dev.driver = NULL;
+ udc->driver = NULL;
+ goto out;
+ }
+
+
+ /* Enable DR IRQ reg and Set usbcmd reg Run bit */
+ dr_controller_run(udc);
+ udc->usb_state = USB_STATE_ATTACHED;
+ udc->ep0_state = WAIT_FOR_SETUP;
+ udc->ep0_dir = 0;
+ udc->vbus_active = vbus_enabled(udc);
+
+ printk(KERN_INFO "%s: bind to driver %s\n",
+ udc->gadget.name, driver->driver.name);
+
+out:
+ if (retval)
+ printk(KERN_WARNING "gadget driver register failed %d\n",
+ retval);
+
+ DBG("%s(%d) END\n", __func__, __LINE__);
+ return retval;
+}
+
+/* Disconnect from gadget driver */
+static int tegra_udc_stop(struct usb_gadget_driver *driver)
+{
+ struct tegra_udc *udc = the_udc;
+ struct tegra_ep *loop_ep;
+ unsigned long flags;
+
+ DBG("%s(%d) BEGIN\n", __func__, __LINE__);
+ if (!udc)
+ return -ENODEV;
+
+ if (!driver || driver != udc->driver || !driver->unbind)
+ return -EINVAL;
+
+ /* stop DR, disable intr */
+ dr_controller_stop(udc);
+
+ /* in fact, no needed */
+ udc->usb_state = USB_STATE_ATTACHED;
+ udc->ep0_state = WAIT_FOR_SETUP;
+ udc->ep0_dir = 0;
+
+ /* stand operation */
+ spin_lock_irqsave(&udc->lock, flags);
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+ nuke(&udc->eps[0], -ESHUTDOWN);
+ list_for_each_entry(loop_ep, &udc->gadget.ep_list,
+ ep.ep_list)
+ nuke(loop_ep, -ESHUTDOWN);
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ /* report disconnect; the controller is already quiesced */
+ driver->disconnect(&udc->gadget);
+
+ /* unbind gadget and unhook driver. */
+ driver->unbind(&udc->gadget);
+ udc->gadget.dev.driver = NULL;
+ udc->driver = NULL;
+
+ printk(KERN_WARNING "unregistered gadget driver '%s'\n",
+ driver->driver.name);
+
+ DBG("%s(%d) END\n", __func__, __LINE__);
+
+ return 0;
+}
+
+
+/* Internal structure setup functions */
+static int tegra_udc_setup_qh(struct tegra_udc *udc)
+{
+ u32 dccparams;
+ size_t size;
+
+ /* Read Device Controller Capability Parameters register */
+ dccparams = udc_readl(udc, DCCPARAMS_REG_OFFSET);
+ if (!(dccparams & DCCPARAMS_DC)) {
+ ERR("This SOC doesn't support device role\n");
+ return -ENODEV;
+ }
+
+ /* Get max device endpoints */
+ /* DEN is bidirectional ep number, max_ep doubles the number */
+ udc->max_ep = (dccparams & DCCPARAMS_DEN_MASK) * 2;
+
+ udc->eps = kzalloc(sizeof(struct tegra_ep) * udc->max_ep, GFP_KERNEL);
+ if (!udc->eps) {
+ ERR("malloc tegra_ep failed\n");
+ return -1;
+ }
+
+ /* Setup hardware queue heads */
+ size = udc->max_ep * sizeof(struct ep_queue_head);
+ udc->ep_qh = (struct ep_queue_head *)((u8 *)(udc->regs) + QH_OFFSET);
+ udc->ep_qh_dma = platform_get_resource(udc->pdev, IORESOURCE_MEM
+ , 0)->start + QH_OFFSET;
+ udc->ep_qh_size = size;
+
+ /* Initialize ep0 status request structure */
+ /* FIXME: tegra_alloc_request() ignores ep argument */
+ udc->status_req = container_of(tegra_alloc_request(NULL, GFP_KERNEL),
+ struct tegra_req, req);
+ /* Allocate a small amount of memory to get valid address */
+ udc->status_req->req.buf = dma_alloc_coherent(&udc->pdev->dev,
+ STATUS_BUFFER_SIZE, &udc->status_req->req.dma,
+ GFP_KERNEL);
+ if (!udc->status_req->req.buf) {
+ ERR("alloc status_req buffer failed\n");
+ kfree(udc->eps);
+ return -ENOMEM;
+ }
+
+ udc->resume_state = USB_STATE_NOTATTACHED;
+ udc->usb_state = USB_STATE_POWERED;
+ udc->ep0_dir = 0;
+ udc->remote_wakeup = 0; /* default to 0 on reset */
+
+ return 0;
+}
+
+/**
+ * Setup the tegra_ep struct for eps
+ * Link tegra_ep->ep to gadget->ep_list
+ * ep0out is not used so do nothing here
+ * ep0in should be taken care
+ */
+static int __init struct_ep_setup(struct tegra_udc *udc, unsigned char index,
+ char *name, int link)
+{
+ struct tegra_ep *ep = &udc->eps[index];
+
+ ep->udc = udc;
+ strcpy(ep->name, name);
+ ep->ep.name = ep->name;
+
+ ep->ep.ops = &tegra_ep_ops;
+ ep->stopped = 0;
+
+ /* for ep0: maxP defined in desc
+ * for other eps, maxP is set by epautoconfig() called by gadget layer
+ */
+ ep->ep.maxpacket = (unsigned short) ~0;
+
+ /* the queue lists any req for this ep */
+ INIT_LIST_HEAD(&ep->queue);
+
+ /* gagdet.ep_list used for ep_autoconfig so no ep0 */
+ if (link)
+ list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+ ep->gadget = &udc->gadget;
+ ep->qh = &udc->ep_qh[index];
+
+ return 0;
+}
+
+static int tegra_udc_ep_setup(struct tegra_udc *udc)
+{
+ /* initialize EP0 descriptor */
+ static const struct usb_endpoint_descriptor tegra_ep0_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 0,
+ .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+ .wMaxPacketSize = USB_MAX_CTRL_PAYLOAD,
+ };
+ int i;
+
+ /* setup QH and epctrl for ep0 */
+ ep0_setup(udc);
+
+ /* setup udc->eps[] for ep0 */
+ struct_ep_setup(udc, 0, "ep0", 0);
+ /* for ep0: the desc defined here;
+ * for other eps, gadget layer called ep_enable with defined desc
+ */
+ udc->eps[0].desc = &tegra_ep0_desc;
+ udc->eps[0].ep.maxpacket = USB_MAX_CTRL_PAYLOAD;
+
+ /* setup the udc->eps[] for non-control endpoints and link
+ * to gadget.ep_list */
+ for (i = 1; i < (int)(udc->max_ep / 2); i++) {
+ char name[14];
+
+ sprintf(name, "ep%dout", i);
+ struct_ep_setup(udc, i * 2, name, 1);
+ sprintf(name, "ep%din", i);
+ struct_ep_setup(udc, i * 2 + 1, name, 1);
+ }
+
+ return 0;
+}
+
+
+/* Driver probe function
+ * all intialization operations implemented here except enabling usb_intr reg
+ * board setup should have been done in the platform code
+ */
+static int __init tegra_udc_probe(struct platform_device *pdev)
+{
+ struct tegra_udc *udc;
+ struct resource *res;
+ int err = -ENODEV;
+ DBG("%s(%d) BEGIN\n", __func__, __LINE__);
+
+ if (strcmp(pdev->name, driver_name)) {
+ VDBG("Wrong device");
+ return -ENODEV;
+ }
+
+ the_udc = udc = kzalloc(sizeof(struct tegra_udc), GFP_KERNEL);
+ if (udc == NULL) {
+ ERR("malloc udc failed\n");
+ return -ENOMEM;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ err = -ENXIO;
+ ERR("failed to get platform resources\n");
+ goto err_kfree;
+ }
+
+ if (!request_mem_region(res->start, res->end - res->start + 1,
+ driver_name)) {
+ ERR("request mem region failed\n");
+ err = -EBUSY;
+ goto err_kfree;
+ }
+
+ udc->regs = ioremap(res->start, resource_size(res));
+ if (!udc->regs) {
+ err = -ENOMEM;
+ ERR("failed to map mem region\n");
+ goto err_rel_mem_region;
+ }
+
+ udc->irq = platform_get_irq(pdev, 0);
+ if (!udc->irq) {
+ err = -ENODEV;
+ ERR("failed to get platform irq resources\n");
+ goto err_iounmap;
+ }
+
+ err = request_irq(udc->irq, tegra_udc_irq,
+ IRQF_SHARED | IRQF_TRIGGER_HIGH,
+ driver_name, udc);
+ if (err) {
+ ERR("cannot request irq %d err %d\n", udc->irq, err);
+ goto err_iounmap;
+ }
+
+ err = enable_irq_wake(udc->irq);
+ if (err < 0) {
+ dev_warn(&pdev->dev,
+ "Couldn't enable USB udc mode wakeup, irq=%d, error=%d\n",
+ udc->irq, err);
+ err = 0;
+ }
+
+ udc->phy = tegra_usb_phy_open(pdev);
+ if (IS_ERR(udc->phy)) {
+ dev_err(&pdev->dev, "failed to open USB phy\n");
+ err = -ENXIO;
+ goto err_irq;
+ }
+
+ err = tegra_usb_phy_power_on(udc->phy);
+ if (err) {
+ dev_err(&pdev->dev, "failed to power on the phy\n");
+ goto err_phy;
+ }
+
+ err = tegra_usb_phy_init(udc->phy);
+ if (err) {
+ dev_err(&pdev->dev, "failed to init the phy\n");
+ goto err_phy;
+ }
+ spin_lock_init(&udc->lock);
+ udc->stopped = 1;
+ udc->pdev = pdev;
+ udc->has_hostpc = tegra_usb_phy_has_hostpc(udc->phy) ? 1 : 0;
+ platform_set_drvdata(pdev, udc);
+
+ /* Initialize the udc structure including QH members */
+ err = tegra_udc_setup_qh(udc);
+ if (err) {
+ dev_err(&pdev->dev, "failed to setup udc QH\n");
+ goto err_phy;
+ }
+
+ /* Initialize usb hw reg except for regs for EP,
+ * leave usbintr reg untouched */
+ err = dr_controller_setup(udc);
+ if (err) {
+ dev_err(&pdev->dev, "failed to setup udc controller\n");
+ goto err_phy;
+ }
+
+ err = tegra_udc_setup_gadget_dev(udc);
+ if (err) {
+ dev_err(&pdev->dev, "failed to setup udc gadget device\n");
+ goto err_phy;
+ }
+
+ err = tegra_udc_ep_setup(udc);
+ if (err) {
+ dev_err(&pdev->dev, "failed to setup end points\n");
+ goto err_unregister;
+ }
+
+ /* Use dma_pool for TD management */
+ udc->td_pool = dma_pool_create("udc_td", &pdev->dev,
+ sizeof(struct ep_td_struct),
+ DTD_ALIGNMENT, UDC_DMA_BOUNDARY);
+ if (!udc->td_pool) {
+ err = -ENOMEM;
+ goto err_unregister;
+ }
+
+ err = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
+ if (err)
+ goto err_del_udc;
+#ifdef CONFIG_TEGRA_GADGET_BOOST_CPU_FREQ
+ boost_cpufreq_work_flag = 1;
+ ep_queue_request_count = 0;
+ INIT_WORK(&udc->boost_cpufreq_work,
+ tegra_udc_boost_cpu_frequency_work);
+ pm_qos_add_request(&boost_cpu_freq_req, PM_QOS_CPU_FREQ_MIN,
+ PM_QOS_DEFAULT_VALUE);
+#endif
+
+ /* Create work for controlling clocks to the phy if otg is disabled */
+ INIT_WORK(&udc->irq_work, tegra_udc_irq_work);
+ /* Create a delayed work for detecting the USB charger */
+ INIT_DELAYED_WORK(&udc->work, tegra_udc_charger_detect_work);
+ INIT_WORK(&udc->charger_work, tegra_udc_set_current_limit_work);
+
+ /* Get the regulator for drawing the vbus current in udc driver */
+ udc->vbus_reg = regulator_get(NULL, "usb_bat_chg");
+ if (IS_ERR(udc->vbus_reg)) {
+ dev_info(&pdev->dev,
+ "usb_bat_chg regulator not registered:"
+ " USB charging will not be enabled\n");
+ udc->vbus_reg = NULL;
+ }
+
+#ifdef CONFIG_USB_OTG_UTILS
+ if (tegra_usb_phy_otg_supported(udc->phy))
+ udc->transceiver = otg_get_transceiver();
+
+ if (udc->transceiver) {
+ dr_controller_stop(udc);
+ dr_controller_reset(udc);
+ tegra_usb_phy_power_off(udc->phy);
+ udc->vbus_active = 0;
+ udc->usb_state = USB_STATE_DEFAULT;
+ otg_set_peripheral(udc->transceiver, &udc->gadget);
+ }
+#else
+ /* Power down the phy if cable is not connected */
+ if (!vbus_enabled())
+ tegra_usb_phy_power_off(udc->phy);
+#endif
+
+ DBG("%s(%d) END\n", __func__, __LINE__);
+ return 0;
+
+err_del_udc:
+ dma_pool_destroy(udc->td_pool);
+
+err_unregister:
+ device_unregister(&udc->gadget.dev);
+
+err_phy:
+ tegra_usb_phy_close(udc->phy);
+
+err_irq:
+ free_irq(udc->irq, udc);
+
+err_iounmap:
+ iounmap(udc->regs);
+
+err_rel_mem_region:
+ release_mem_region(res->start, res->end - res->start + 1);
+
+err_kfree:
+ kfree(udc);
+
+ return err;
+}
+
+/* Driver removal function
+ * Free resources and finish pending transactions
+ */
+static int __exit tegra_udc_remove(struct platform_device *pdev)
+{
+ struct tegra_udc *udc = platform_get_drvdata(pdev);
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ DECLARE_COMPLETION(done);
+
+ if (!udc)
+ return -ENODEV;
+
+ usb_del_gadget_udc(&udc->gadget);
+ udc->done = &done;
+
+ cancel_delayed_work(&udc->work);
+#ifdef CONFIG_TEGRA_GADGET_BOOST_CPU_FREQ
+ cancel_work_sync(&udc->boost_cpufreq_work);
+#endif
+
+ if (udc->vbus_reg)
+ regulator_put(udc->vbus_reg);
+
+ if (udc->transceiver)
+ otg_set_peripheral(udc->transceiver, NULL);
+
+
+ /* Free allocated memory */
+ dma_free_coherent(&pdev->dev, STATUS_BUFFER_SIZE,
+ udc->status_req->req.buf,
+ udc->status_req->req.dma);
+ kfree(udc->status_req);
+ kfree(udc->eps);
+
+ dma_pool_destroy(udc->td_pool);
+ free_irq(udc->irq, udc);
+ iounmap(udc->regs);
+ release_mem_region(res->start, res->end - res->start + 1);
+
+ device_unregister(&udc->gadget.dev);
+ /* Free udc -- wait for the release() finished */
+ wait_for_completion(&done);
+
+ return 0;
+}
+
+static int tegra_udc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct tegra_udc *udc = platform_get_drvdata(pdev);
+ unsigned long flags;
+ DBG("%s(%d) BEGIN\n", __func__, __LINE__);
+
+ /* If the controller is in otg mode, return */
+ if (udc->transceiver)
+ return 0;
+
+ if (udc->vbus_active) {
+ spin_lock_irqsave(&udc->lock, flags);
+ /* Reset all internal Queues and inform client driver */
+ reset_queues(udc);
+ udc->vbus_active = 0;
+ udc->usb_state = USB_STATE_DEFAULT;
+ spin_unlock_irqrestore(&udc->lock, flags);
+ }
+ /* Stop the controller and turn off the clocks */
+ dr_controller_stop(udc);
+ if (udc->transceiver)
+ udc->transceiver->state = OTG_STATE_UNDEFINED;
+
+ tegra_usb_phy_power_off(udc->phy);
+
+ DBG("%s(%d) END\n", __func__, __LINE__);
+ return 0;
+}
+
+static int tegra_udc_resume(struct platform_device *pdev)
+{
+ struct tegra_udc *udc = platform_get_drvdata(pdev);
+ DBG("%s(%d) BEGIN\n", __func__, __LINE__);
+
+ if (udc->transceiver)
+ return 0;
+
+ tegra_usb_phy_power_on(udc->phy);
+ tegra_udc_restart(udc);
+
+ /* Power down the phy if cable is not connected */
+ if (!vbus_enabled(udc)) {
+ udc->vbus_active = 0;
+ tegra_usb_phy_power_off(udc->phy);
+ }
+
+ DBG("%s(%d) END\n", __func__, __LINE__);
+ return 0;
+}
+
+
+static struct platform_driver tegra_udc_driver = {
+ .remove = __exit_p(tegra_udc_remove),
+ .suspend = tegra_udc_suspend,
+ .resume = tegra_udc_resume,
+ .driver = {
+ .name = (char *)driver_name,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init udc_init(void)
+{
+ printk(KERN_INFO "%s (%s)\n", driver_desc, DRIVER_VERSION);
+ return platform_driver_probe(&tegra_udc_driver, tegra_udc_probe);
+}
+module_init(udc_init);
+static void __exit udc_exit(void)
+{
+ platform_driver_unregister(&tegra_udc_driver);
+ printk(KERN_WARNING "%s unregistered\n", driver_desc);
+}
+module_exit(udc_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:tegra-udc");
diff --git a/drivers/usb/gadget/tegra_udc.h b/drivers/usb/gadget/tegra_udc.h
new file mode 100644
index 000000000000..e94543fd98e3
--- /dev/null
+++ b/drivers/usb/gadget/tegra_udc.h
@@ -0,0 +1,440 @@
+/*
+ * Copyright (C) 2011 NVIDIA Corporation
+ *
+ * Description:
+ * High-speed USB device controller driver.
+ * USB device/endpoint management registers.
+ * The driver is previously named as fsl_udc_core. Based on Freescale driver
+ * code from Li Yang and Jiang Bo.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the 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 __TEGRA_UDC_H
+#define __TEGRA_UDC_H
+
+#ifdef VERBOSE
+#define VDBG(fmt, args...) printk(KERN_DEBUG "[%s] " fmt "\n", \
+ __func__, ## args)
+#else
+#define VDBG(fmt, args...) do {} while (0)
+#endif
+
+
+#ifdef DEBUG
+#define DBG(stuff...) pr_info("tegra_udc: " stuff)
+#else
+#define DBG(stuff...) do {} while (0)
+#endif
+
+#define ERR(stuff...) pr_err("tegra_udc: " stuff)
+#define WARNING(stuff...) pr_warning("tegra_udc: " stuff)
+
+#define DMA_ADDR_INVALID (~(dma_addr_t)0)
+#define STATUS_BUFFER_SIZE 8
+
+#define USB_MAX_CTRL_PAYLOAD 64
+
+ /* Charger current limit=1800mA, as per the USB charger spec */
+#define USB_CHARGING_CURRENT_LIMIT_MA 1800
+ /* 1 sec wait time for charger detection after vbus is detected */
+#define USB_CHARGER_DETECTION_WAIT_TIME_MS 1000
+#define BOOST_TRIGGER_SIZE 4096
+
+#define UDC_RESET_TIMEOUT_MS 1000
+#define UDC_RUN_TIMEOUT_MS 1000
+#define UDC_FLUSH_TIMEOUT_MS 1000
+
+/* ep0 transfer state */
+#define WAIT_FOR_SETUP 0
+#define DATA_STATE_XMIT 1
+#define DATA_STATE_NEED_ZLP 2
+#define WAIT_FOR_OUT_STATUS 3
+#define DATA_STATE_RECV 4
+
+/*
+ * ### pipe direction macro from device view
+ */
+#define USB_RECV 0 /* OUT EP */
+#define USB_SEND 1 /* IN EP */
+
+/* Device Controller Capability Parameter register */
+#define DCCPARAMS_REG_OFFSET 0x124
+#define DCCPARAMS_DC 0x00000080
+#define DCCPARAMS_DEN_MASK 0x0000001f
+
+/* USB CMD Register Bit Masks */
+#define USB_CMD_REG_OFFSET ((udc->has_hostpc) ? 0x130 : 0x140)
+#define USB_CMD_RUN_STOP 0x00000001
+#define USB_CMD_CTRL_RESET 0x00000002
+#define USB_CMD_PERIODIC_SCHEDULE_EN 0x00000010
+#define USB_CMD_ASYNC_SCHEDULE_EN 0x00000020
+#define USB_CMD_INT_AA_DOORBELL 0x00000040
+#define USB_CMD_ASP 0x00000300
+#define USB_CMD_ASYNC_SCH_PARK_EN 0x00000800
+#define USB_CMD_SUTW 0x00002000
+#define USB_CMD_ATDTW 0x00004000
+#define USB_CMD_ITC 0x00FF0000
+/* bit 15,3,2 are frame list size */
+#define USB_CMD_FRAME_SIZE_1024 0x00000000
+#define USB_CMD_FRAME_SIZE_512 0x00000004
+#define USB_CMD_FRAME_SIZE_256 0x00000008
+#define USB_CMD_FRAME_SIZE_128 0x0000000C
+#define USB_CMD_FRAME_SIZE_64 0x00008000
+#define USB_CMD_FRAME_SIZE_32 0x00008004
+#define USB_CMD_FRAME_SIZE_16 0x00008008
+#define USB_CMD_FRAME_SIZE_8 0x0000800C
+/* bit 9-8 are async schedule park mode count */
+#define USB_CMD_ASP_00 0x00000000
+#define USB_CMD_ASP_01 0x00000100
+#define USB_CMD_ASP_10 0x00000200
+#define USB_CMD_ASP_11 0x00000300
+#define USB_CMD_ASP_BIT_POS 8
+/* bit 23-16 are interrupt threshold control */
+#define USB_CMD_ITC_NO_THRESHOLD 0x00000000
+#define USB_CMD_ITC_1_MICRO_FRM 0x00010000
+#define USB_CMD_ITC_2_MICRO_FRM 0x00020000
+#define USB_CMD_ITC_4_MICRO_FRM 0x00040000
+#define USB_CMD_ITC_8_MICRO_FRM 0x00080000
+#define USB_CMD_ITC_16_MICRO_FRM 0x00100000
+#define USB_CMD_ITC_32_MICRO_FRM 0x00200000
+#define USB_CMD_ITC_64_MICRO_FRM 0x00400000
+#define USB_CMD_ITC_BIT_POS 16
+
+/* USB STS Register Bit Masks */
+#define USB_STS_REG_OFFSET ((udc->has_hostpc) ? 0x134 : 0x144)
+#define USB_STS_INT 0x00000001
+#define USB_STS_ERR 0x00000002
+#define USB_STS_PORT_CHANGE 0x00000004
+#define USB_STS_FRM_LST_ROLL 0x00000008
+#define USB_STS_SYS_ERR 0x00000010
+#define USB_STS_IAA 0x00000020
+#define USB_STS_RESET 0x00000040
+#define USB_STS_SOF 0x00000080
+#define USB_STS_SUSPEND 0x00000100
+#define USB_STS_HC_HALTED 0x00001000
+#define USB_STS_RCL 0x00002000
+#define USB_STS_PERIODIC_SCHEDULE 0x00004000
+#define USB_STS_ASYNC_SCHEDULE 0x00008000
+
+/* USB INTR Register Bit Masks */
+#define USB_INTR_REG_OFFSET ((udc->has_hostpc) ? 0x138 : 0x148)
+#define USB_INTR_INT_EN 0x00000001
+#define USB_INTR_ERR_INT_EN 0x00000002
+#define USB_INTR_PTC_DETECT_EN 0x00000004
+#define USB_INTR_FRM_LST_ROLL_EN 0x00000008
+#define USB_INTR_SYS_ERR_EN 0x00000010
+#define USB_INTR_ASYN_ADV_EN 0x00000020
+#define USB_INTR_RESET_EN 0x00000040
+#define USB_INTR_SOF_EN 0x00000080
+#define USB_INTR_DEVICE_SUSPEND 0x00000100
+
+/* Frame Index Register Bit Masks */
+#define USB_FRINDEX_REG_OFFSET ((udc->has_hostpc) ? 0x13c : 0x14c)
+#define USB_FRINDEX_MASKS 0x3fff
+
+/* Device Address bit masks */
+#define USB_DEVICE_ADDR_REG_OFFSET ((udc->has_hostpc) ? 0x144 : 0x154)
+#define USB_DEVICE_ADDRESS_MASK 0xFE000000
+#define USB_DEVICE_ADDRESS_BIT_POS 25
+
+/* endpoint list address bit masks */
+#define USB_EP_LIST_ADDRESS_REG_OFFSET ((udc->has_hostpc) ? 0x148 : 0x158)
+#define USB_EP_LIST_ADDRESS_MASK 0xfffff800
+
+/* PORTSCX Register Bit Masks */
+#define PORTSCX_REG_OFFSET ((udc->has_hostpc) ? 0x174 : 0x184)
+#define PORTSCX_CURRENT_CONNECT_STATUS 0x00000001
+#define PORTSCX_CONNECT_STATUS_CHANGE 0x00000002
+#define PORTSCX_PORT_ENABLE 0x00000004
+#define PORTSCX_PORT_EN_DIS_CHANGE 0x00000008
+#define PORTSCX_OVER_CURRENT_ACT 0x00000010
+#define PORTSCX_OVER_CURRENT_CHG 0x00000020
+#define PORTSCX_PORT_FORCE_RESUME 0x00000040
+#define PORTSCX_PORT_SUSPEND 0x00000080
+#define PORTSCX_PORT_RESET 0x00000100
+#define PORTSCX_LINE_STATUS_BITS 0x00000C00
+#define PORTSCX_PORT_POWER 0x00001000
+#define PORTSCX_PORT_INDICTOR_CTRL 0x0000C000
+#define PORTSCX_PORT_TEST_CTRL 0x000F0000
+#define PORTSCX_WAKE_ON_CONNECT_EN 0x00100000
+#define PORTSCX_WAKE_ON_CONNECT_DIS 0x00200000
+#define PORTSCX_WAKE_ON_OVER_CURRENT 0x00400000
+#define PORTSCX_PHY_LOW_POWER_SPD 0x00800000
+
+/* In tegra3 the following fields have moved to new HOSTPC1_DEVLC reg and
+ * their offsets have changed.
+ * Keeping the name of bit masks same as before (PORTSCX_*) to have
+ * minimum changes to code */
+#define USB_HOSTPCX_DEVLC_REG_OFFSET 0x1b4
+
+#define PORTSCX_PORT_FORCE_FULL_SPEED ((udc->has_hostpc) ? 0x00800000 \
+ : 0x01000000)
+#define PORTSCX_PORT_SPEED_MASK ((udc->has_hostpc) ? 0x06000000 : 0x0C000000)
+#define PORTSCX_PORT_WIDTH ((udc->has_hostpc) ? 0x08000000 : 0x10000000)
+#define PORTSCX_PHY_TYPE_SEL ((udc->has_hostpc) ? 0xE0000000 : 0xC0000000)
+
+/* bits for port speed */
+#define PORTSCX_PORT_SPEED_FULL ((udc->has_hostpc) ? 0x00000000 : 0x00000000)
+#define PORTSCX_PORT_SPEED_LOW ((udc->has_hostpc) ? 0x02000000 : 0x04000000)
+#define PORTSCX_PORT_SPEED_HIGH ((udc->has_hostpc) ? 0x04000000 : 0x08000000)
+#define PORTSCX_PORT_SPEED_UNDEF ((udc->has_hostpc) ? 0x06000000 : 0x0C000000)
+#define PORTSCX_SPEED_BIT_POS ((udc->has_hostpc) ? 25 : 26)
+
+/* bits for parallel transceiver width for UTMI interface */
+#define PORTSCX_PTW ((udc->has_hostpc) ? 0x08000000 : 0x10000000)
+#define PORTSCX_PTW_8BIT ((udc->has_hostpc) ? 0x00000000 : 0x00000000)
+#define PORTSCX_PTW_16BIT ((udc->has_hostpc) ? 0x08000000 : 0x10000000)
+
+/* bits for port transceiver select */
+#define PORTSCX_PTS_UTMI ((udc->has_hostpc) ? 0x00000000 : 0x00000000)
+#define PORTSCX_PTS_ULPI ((udc->has_hostpc) ? 0x40000000 : 0x80000000)
+#define PORTSCX_PTS_FSLS ((udc->has_hostpc) ? 0x60000000 : 0xC0000000)
+#define PORTSCX_PTS_BIT_POS ((udc->has_hostpc) ? 29 : 30)
+
+/* bit 11-10 are line status */
+#define PORTSCX_LINE_STATUS_SE0 0x00000000
+#define PORTSCX_LINE_STATUS_JSTATE 0x00000400
+#define PORTSCX_LINE_STATUS_KSTATE 0x00000800
+#define PORTSCX_LINE_STATUS_UNDEF 0x00000C00
+#define PORTSCX_LINE_STATUS_BIT_POS 10
+
+/* bit 15-14 are port indicator control */
+#define PORTSCX_PIC_OFF 0x00000000
+#define PORTSCX_PIC_AMBER 0x00004000
+#define PORTSCX_PIC_GREEN 0x00008000
+#define PORTSCX_PIC_UNDEF 0x0000C000
+#define PORTSCX_PIC_BIT_POS 14
+
+/* bit 19-16 are port test control */
+#define PORTSCX_PTC_DISABLE 0x00000000
+#define PORTSCX_PTC_JSTATE 0x00010000
+#define PORTSCX_PTC_KSTATE 0x00020000
+#define PORTSCX_PTC_SEQNAK 0x00030000
+#define PORTSCX_PTC_PACKET 0x00040000
+#define PORTSCX_PTC_FORCE_EN 0x00050000
+#define PORTSCX_PTC_BIT_POS 16
+
+
+/* USB MODE Register Bit Masks */
+#define USB_MODE_REG_OFFSET ((udc->has_hostpc) ? 0x1f8 : 0x1a8)
+#define USB_MODE_CTRL_MODE_IDLE 0x00000000
+#define USB_MODE_CTRL_MODE_DEVICE 0x00000002
+#define USB_MODE_CTRL_MODE_HOST 0x00000003
+#define USB_MODE_CTRL_MODE_RSV 0x00000001
+#define USB_MODE_SETUP_LOCK_OFF 0x00000008
+#define USB_MODE_STREAM_DISABLE 0x00000010
+
+/* Endpoint Setup Status bit masks */
+#define EP_SETUP_STATUS_REG_OFFSET ((udc->has_hostpc) ? 0x208 : 0x1ac)
+#define EP_SETUP_STATUS_MASK 0x0000003F
+#define EP_SETUP_STATUS_EP0 0x00000001
+
+/* Endpoint Prime Register */
+#define EP_PRIME_REG_OFFSET ((udc->has_hostpc) ? 0x20c : 0x1b0)
+
+/* Endpoint Flush Register */
+#define EPFLUSH_REG_OFFSET ((udc->has_hostpc) ? 0x210 : 0x1b4)
+#define EPFLUSH_TX_OFFSET 0x00010000
+#define EPFLUSH_RX_OFFSET 0x00000000
+
+/* Endpoint Status Register */
+#define EP_STATUS_REG_OFFSET ((udc->has_hostpc) ? 0x214 : 0x1b8)
+
+/* Endpoint Complete Register */
+#define EP_COMPLETE_REG_OFFSET ((udc->has_hostpc) ? 0x218 : 0x1bc)
+
+/* Endpoint Control Registers */
+#define EP_CONTROL_REG_OFFSET ((udc->has_hostpc) ? 0x21c : 0x1c0)
+
+/* ENDPOINTCTRLx Register Bit Masks */
+#define EPCTRL_TX_ENABLE 0x00800000
+#define EPCTRL_TX_DATA_TOGGLE_RST 0x00400000 /* Not EP0 */
+#define EPCTRL_TX_DATA_TOGGLE_INH 0x00200000 /* Not EP0 */
+#define EPCTRL_TX_TYPE 0x000C0000
+#define EPCTRL_TX_DATA_SOURCE 0x00020000 /* Not EP0 */
+#define EPCTRL_TX_EP_STALL 0x00010000
+#define EPCTRL_RX_ENABLE 0x00000080
+#define EPCTRL_RX_DATA_TOGGLE_RST 0x00000040 /* Not EP0 */
+#define EPCTRL_RX_DATA_TOGGLE_INH 0x00000020 /* Not EP0 */
+#define EPCTRL_RX_TYPE 0x0000000C
+#define EPCTRL_RX_DATA_SINK 0x00000002 /* Not EP0 */
+#define EPCTRL_RX_EP_STALL 0x00000001
+
+/* bit 19-18 and 3-2 are endpoint type */
+#define EPCTRL_EP_TYPE_CONTROL 0
+#define EPCTRL_EP_TYPE_ISO 1
+#define EPCTRL_EP_TYPE_BULK 2
+#define EPCTRL_EP_TYPE_INTERRUPT 3
+#define EPCTRL_TX_EP_TYPE_SHIFT 18
+#define EPCTRL_RX_EP_TYPE_SHIFT 2
+
+#define VBUS_SENSOR_REG_OFFSET 0x404
+#define VBUS_WAKEUP_REG_OFFSET 0x408
+
+#define USB_SYS_VBUS_ASESSION_INT_EN 0x10000
+#define USB_SYS_VBUS_ASESSION_CHANGED 0x20000
+#define USB_SYS_VBUS_ASESSION 0x40000
+#define USB_SYS_VBUS_WAKEUP_ENABLE 0x40000000
+#define USB_SYS_VBUS_WAKEUP_INT_ENABLE 0x100
+#define USB_SYS_VBUS_WAKEUP_INT_STATUS 0x200
+#define USB_SYS_VBUS_STATUS 0x400
+#define USB_SYS_ID_PIN_STATUS 0x4
+
+
+/* Endpoint Queue Head Bit Masks */
+#define EP_QUEUE_HEAD_MULT_POS 30
+#define EP_QUEUE_HEAD_ZLT_SEL 0x20000000
+#define EP_QUEUE_HEAD_MAX_PKT_LEN_POS 16
+#define EP_QUEUE_HEAD_MAX_PKT_LEN(ep_info) (((ep_info)>>16)&0x07ff)
+#define EP_QUEUE_HEAD_IOS 0x00008000
+#define EP_QUEUE_HEAD_NEXT_TERMINATE 0x00000001
+#define EP_QUEUE_HEAD_IOC 0x00008000
+#define EP_QUEUE_HEAD_MULTO 0x00000C00
+#define EP_QUEUE_HEAD_STATUS_HALT 0x00000040
+#define EP_QUEUE_HEAD_STATUS_ACTIVE 0x00000080
+#define EP_QUEUE_CURRENT_OFFSET_MASK 0x00000FFF
+#define EP_QUEUE_HEAD_NEXT_POINTER_MASK 0xFFFFFFE0
+#define EP_QUEUE_FRINDEX_MASK 0x000007FF
+#define EP_MAX_LENGTH_TRANSFER 0x4000
+
+
+
+/* Endpoint Transfer Descriptor bit Masks */
+#define DTD_NEXT_TERMINATE 0x00000001
+#define DTD_IOC 0x00008000
+#define DTD_STATUS_ACTIVE 0x00000080
+#define DTD_STATUS_HALTED 0x00000040
+#define DTD_STATUS_DATA_BUFF_ERR 0x00000020
+#define DTD_STATUS_TRANSACTION_ERR 0x00000008
+#define DTD_RESERVED_FIELDS 0x80007300
+#define DTD_ADDR_MASK 0xFFFFFFE0
+#define DTD_PACKET_SIZE 0x7FFF0000
+#define DTD_LENGTH_BIT_POS 16
+#define DTD_ERROR_MASK (DTD_STATUS_HALTED | \
+ DTD_STATUS_DATA_BUFF_ERR | \
+ DTD_STATUS_TRANSACTION_ERR)
+/* Alignment requirements; must be a power of two */
+#define DTD_ALIGNMENT 0x80
+#define QH_ALIGNMENT 2048
+#define QH_OFFSET 0x1000
+
+/* Controller dma boundary */
+#define UDC_DMA_BOUNDARY 0x1000
+
+#define REQ_UNCOMPLETE 1
+
+#define EP_DIR_IN 1
+#define EP_DIR_OUT 0
+
+/*
+ * Endpoint Queue Head data struct
+ * Rem: all the variables of qh are LittleEndian Mode
+ * and NEXT_POINTER_MASK should operate on a LittleEndian, Phy Addr
+ */
+struct ep_queue_head {
+ u32 max_pkt_length; /* Mult(31-30), Zlt(29), Max Pkt len and IOS(15) */
+ u32 curr_dtd_ptr; /* Current dTD Pointer(31-5) */
+ u32 next_dtd_ptr; /* Next dTD Pointer(31-5), T(0) */
+ u32 size_ioc_int_sts; /* Total bytes (30-16), IOC (15),
+ MultO(11-10), STS (7-0) */
+ u32 buff_ptr0; /* Buffer pointer Page 0 (31-12) */
+ u32 buff_ptr1; /* Buffer pointer Page 1 (31-12) */
+ u32 buff_ptr2; /* Buffer pointer Page 2 (31-12) */
+ u32 buff_ptr3; /* Buffer pointer Page 3 (31-12) */
+ u32 buff_ptr4; /* Buffer pointer Page 4 (31-12) */
+ u32 res1;
+ u8 setup_buffer[8]; /* Setup data 8 bytes */
+ u32 res2[4];
+};
+
+/* Endpoint Transfer Descriptor data struct */
+/* Rem: all the variables of td are LittleEndian Mode */
+struct ep_td_struct {
+ u32 next_td_ptr; /* Next TD pointer(31-5), T(0) set
+ indicate invalid */
+ u32 size_ioc_sts; /* Total bytes (30-16), IOC (15),
+ MultO(11-10), STS (7-0) */
+ u32 buff_ptr0; /* Buffer pointer Page 0 */
+ u32 buff_ptr1; /* Buffer pointer Page 1 */
+ u32 buff_ptr2; /* Buffer pointer Page 2 */
+ u32 buff_ptr3; /* Buffer pointer Page 3 */
+ u32 buff_ptr4; /* Buffer pointer Page 4 */
+ u32 res;
+ /* 32 bytes */
+ dma_addr_t td_dma; /* dma address for this td */
+ /* virtual address of next td specified in next_td_ptr */
+ struct ep_td_struct *next_td_virt;
+};
+
+
+struct tegra_req {
+ struct usb_request req;
+ struct list_head queue;
+ /* ep_queue() func will add
+ a request->queue into a udc_ep->queue 'd tail */
+ struct tegra_ep *ep;
+ unsigned mapped:1;
+
+ struct ep_td_struct *head, *tail; /* For dTD List
+ cpu endian Virtual addr */
+ unsigned int dtd_count;
+};
+
+struct tegra_ep {
+ struct usb_ep ep;
+ struct list_head queue;
+ struct tegra_udc *udc;
+ struct ep_queue_head *qh;
+ const struct usb_endpoint_descriptor *desc;
+ struct usb_gadget *gadget;
+
+ char name[14];
+ unsigned stopped:1;
+};
+
+struct tegra_udc {
+ struct usb_gadget gadget;
+ struct usb_gadget_driver *driver;
+ struct completion *done; /* to make sure release() is done */
+ struct tegra_ep *eps;
+ struct platform_device *pdev;
+ struct tegra_usb_phy *phy;
+ struct usb_ctrlrequest local_setup_buff;
+ struct otg_transceiver *transceiver;
+ struct ep_queue_head *ep_qh; /* Endpoints Queue-Head */
+ struct tegra_req *status_req; /* ep0 status request */
+ struct dma_pool *td_pool; /* dma pool for DTD */
+ struct delayed_work work; /* delayed work for charger detection */
+ struct regulator *vbus_reg; /* regulator for drawing VBUS */
+ /* work for setting regulator current limit */
+ struct work_struct charger_work;
+ /* work for boosting cpu frequency */
+ struct work_struct boost_cpufreq_work;
+ /* irq work for controlling the usb power */
+ struct work_struct irq_work;
+ void __iomem *regs;
+ size_t ep_qh_size; /* size after alignment adjustment*/
+ dma_addr_t ep_qh_dma; /* dma address of QH */
+ unsigned int max_ep;
+ unsigned int irq;
+ u32 max_pipes; /* Device max pipes */
+ u32 resume_state; /* USB state to resume */
+ u32 usb_state; /* USB current state */
+ u32 ep0_state; /* Endpoint zero state */
+ u32 ep0_dir; /* Endpoint zero direction: USB_DIR_IN/USB_DIR_OUT */
+ u8 device_address; /* Device USB address */
+ u32 current_limit;
+ spinlock_t lock;
+ unsigned softconnect:1;
+ unsigned vbus_active:1;
+ unsigned stopped:1;
+ unsigned remote_wakeup:1;
+ unsigned selfpowered:1;
+ bool has_hostpc;
+};
+
+
+#endif /* __TEGRA_UDC_H */
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 25ed607aab9a..bf171c180987 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -145,7 +145,7 @@ static __maybe_unused void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
spin_lock_irqsave(&ehci->lock, flags);
/* clear phy low-power mode before changing wakeup flags */
- if (ehci->has_hostpc) {
+ if (ehci->has_hostpc && !ehci->broken_hostpc_phcd) {
port = HCS_N_PORTS(ehci->hcs_params);
while (port--) {
u32 __iomem *hostpc_reg;
@@ -181,7 +181,7 @@ static __maybe_unused void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
}
/* enter phy low-power mode again */
- if (ehci->has_hostpc) {
+ if (ehci->has_hostpc && !ehci->broken_hostpc_phcd) {
port = HCS_N_PORTS(ehci->hcs_params);
while (port--) {
u32 __iomem *hostpc_reg;
@@ -285,7 +285,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
}
}
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- if (changed && ehci->has_hostpc) {
+ if (changed && ehci->has_hostpc && !ehci->broken_hostpc_phcd) {
spin_unlock_irq(&ehci->lock);
msleep(5); /* 5 ms for HCD to enter low-power mode */
spin_lock_irq(&ehci->lock);
@@ -389,7 +389,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
spin_lock_irq(&ehci->lock);
/* clear phy low-power mode before resume */
- if (ehci->bus_suspended && ehci->has_hostpc) {
+ if (ehci->bus_suspended && ehci->has_hostpc && !ehci->broken_hostpc_phcd) {
i = HCS_N_PORTS(ehci->hcs_params);
while (i--) {
if (test_bit(i, &ehci->bus_suspended)) {
@@ -731,7 +731,7 @@ static int ehci_hub_control (
goto error;
/* clear phy low-power mode before resume */
- if (hostpc_reg) {
+ if (hostpc_reg && !ehci->broken_hostpc_phcd) {
temp1 = ehci_readl(ehci, hostpc_reg);
ehci_writel(ehci, temp1 & ~HOSTPC_PHCD,
hostpc_reg);
@@ -979,7 +979,7 @@ static int ehci_hub_control (
temp &= ~PORT_WKCONN_E;
temp |= PORT_WKDISC_E | PORT_WKOC_E;
ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
- if (hostpc_reg) {
+ if (hostpc_reg && !ehci->broken_hostpc_phcd) {
spin_unlock_irqrestore(&ehci->lock, flags);
msleep(5);/* 5ms for HCD enter low pwr mode */
spin_lock_irqsave(&ehci->lock, flags);
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index 5e646b65b3f0..33504e402611 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -1,8 +1,8 @@
/*
* EHCI-compliant USB host controller driver for NVIDIA Tegra SoCs
*
- * Copyright (C) 2010 Google, Inc.
- * Copyright (C) 2009 - 2012 NVIDIA Corporation
+ * Copyright (c) 2010 Google, Inc.
+ * Copyright (c) 2009-2012 NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -16,7 +16,6 @@
*
*/
-#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/platform_data/tegra_usb.h>
#include <linux/irq.h>
@@ -24,191 +23,158 @@
#include <mach/usb_phy.h>
#include <mach/iomap.h>
-#define TEGRA_USB_PORTSC_PHCD (1 << 23)
-
-#define TEGRA_USB_SUSP_CTRL_OFFSET 0x400
-#define TEGRA_USB_SUSP_CLR (1 << 5)
-#define TEGRA_USB_PHY_CLK_VALID (1 << 7)
-#define TEGRA_USB_SRT (1 << 25)
-#define TEGRA_USB_PHY_CLK_VALID_INT_ENB (1 << 9)
-#define TEGRA_USB_PHY_CLK_VALID_INT_STS (1 << 8)
-
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
-#define TEGRA_USB_PORTSC1_OFFSET 0x184
+#if 0
+#define EHCI_DBG(stuff...) pr_info("ehci-tegra: " stuff)
#else
-#define TEGRA_USB_PORTSC1_OFFSET 0x174
+#define EHCI_DBG(stuff...) do {} while (0)
#endif
-#define TEGRA_USB_PORTSC1_WKCN (1 << 20)
-#define TEGRA_LVL2_CLK_GATE_OVRB 0xfc
-#define TEGRA_USB2_CLK_OVR_ON (1 << 10)
+static const char driver_name[] = "tegra-ehci";
#define TEGRA_USB_DMA_ALIGN 32
-#define STS_SRI (1<<7) /* SOF Recieved */
-
-#define HOSTPC_REG_OFFSET 0x1b4
-
-#define HOSTPC1_DEVLC_STS (1 << 28)
-#define HOSTPC1_DEVLC_PTS(x) (((x) & 0x7) << 29)
-
-#define USB1_PREFETCH_ID 6
-#define USB2_PREFETCH_ID 18
-#define USB3_PREFETCH_ID 17
-
struct tegra_ehci_hcd {
struct ehci_hcd *ehci;
struct tegra_usb_phy *phy;
- struct clk *clk;
- struct clk *emc_clk;
- struct clk *sclk_clk;
+#ifdef CONFIG_USB_OTG_UTILS
struct otg_transceiver *transceiver;
- int host_resumed;
- int bus_suspended;
- int port_resuming;
- int power_down_on_bus_suspend;
- int default_enable;
- enum tegra_usb_phy_port_speed port_speed;
- struct work_struct clk_timer_work;
- struct timer_list clk_timer;
- bool clock_enabled;
- bool timer_event;
- struct mutex tegra_ehci_hcd_mutex;
+#endif
+ struct mutex sync_lock;
+ bool port_resuming;
unsigned int irq;
bool bus_suspended_fail;
};
-static void tegra_ehci_power_up(struct usb_hcd *hcd, bool is_dpd)
+struct dma_align_buffer {
+ void *kmalloc_ptr;
+ void *old_xfer_buffer;
+ u8 data[0];
+};
+
+static void free_align_buffer(struct urb *urb)
{
- struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
+ struct dma_align_buffer *temp = container_of(urb->transfer_buffer,
+ struct dma_align_buffer, data);
+
+ if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER))
+ return;
+
+ /* In transaction, DMA from Device */
+ if (usb_urb_dir_in(urb))
+ memcpy(temp->old_xfer_buffer, temp->data,
+ urb->transfer_buffer_length);
- if (!tegra->default_enable)
- clk_enable(tegra->clk);
- tegra_usb_phy_power_on(tegra->phy, is_dpd);
- tegra->host_resumed = 1;
+ urb->transfer_buffer = temp->old_xfer_buffer;
+ urb->transfer_flags &= ~URB_ALIGNED_TEMP_BUFFER;
+ kfree(temp->kmalloc_ptr);
}
-static void tegra_ehci_power_down(struct usb_hcd *hcd, bool is_dpd)
+static int alloc_align_buffer(struct urb *urb, gfp_t mem_flags)
{
- struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
+ struct dma_align_buffer *temp, *kmalloc_ptr;
+ size_t kmalloc_size;
- tegra->host_resumed = 0;
- tegra_usb_phy_power_off(tegra->phy, is_dpd);
- if (!tegra->default_enable)
- clk_disable(tegra->clk);
+ if (urb->num_sgs || urb->sg ||
+ urb->transfer_buffer_length == 0 ||
+ !((uintptr_t)urb->transfer_buffer & (TEGRA_USB_DMA_ALIGN - 1)))
+ return 0;
+
+ /* Allocate a buffer with enough padding for alignment */
+ kmalloc_size = urb->transfer_buffer_length +
+ sizeof(struct dma_align_buffer) + TEGRA_USB_DMA_ALIGN - 1;
+ kmalloc_ptr = kmalloc(kmalloc_size, mem_flags);
+
+ if (!kmalloc_ptr)
+ return -ENOMEM;
+
+ /* Position our struct dma_align_buffer such that data is aligned */
+ temp = PTR_ALIGN(kmalloc_ptr + 1, TEGRA_USB_DMA_ALIGN) - 1;
+ temp->kmalloc_ptr = kmalloc_ptr;
+ temp->old_xfer_buffer = urb->transfer_buffer;
+ /* OUT transaction, DMA to Device */
+ if (!usb_urb_dir_in(urb))
+ memcpy(temp->data, urb->transfer_buffer,
+ urb->transfer_buffer_length);
+
+ urb->transfer_buffer = temp->data;
+ urb->transfer_flags |= URB_ALIGNED_TEMP_BUFFER;
+
+ return 0;
}
-static int tegra_ehci_internal_port_reset(
- struct ehci_hcd *ehci,
- u32 __iomem *portsc_reg
-)
+static int tegra_ehci_map_urb_for_dma(struct usb_hcd *hcd,
+ struct urb *urb, gfp_t mem_flags)
{
- u32 temp;
- unsigned long flags;
- int retval = 0;
- int i, tries;
- u32 saved_usbintr;
-
- spin_lock_irqsave(&ehci->lock, flags);
- saved_usbintr = ehci_readl(ehci, &ehci->regs->intr_enable);
- /* disable USB interrupt */
- ehci_writel(ehci, 0, &ehci->regs->intr_enable);
- spin_unlock_irqrestore(&ehci->lock, flags);
-
- /*
- * Here we have to do Port Reset at most twice for
- * Port Enable bit to be set.
- */
- for (i = 0; i < 2; i++) {
- temp = ehci_readl(ehci, portsc_reg);
- temp |= PORT_RESET;
- ehci_writel(ehci, temp, portsc_reg);
- mdelay(10);
- temp &= ~PORT_RESET;
- ehci_writel(ehci, temp, portsc_reg);
- mdelay(1);
- tries = 100;
- do {
- mdelay(1);
- /*
- * Up to this point, Port Enable bit is
- * expected to be set after 2 ms waiting.
- * USB1 usually takes extra 45 ms, for safety,
- * we take 100 ms as timeout.
- */
- temp = ehci_readl(ehci, portsc_reg);
- } while (!(temp & PORT_PE) && tries--);
- if (temp & PORT_PE)
- break;
+ int ret;
+
+ ret = alloc_align_buffer(urb, mem_flags);
+ if (ret)
+ return ret;
+
+ ret = usb_hcd_map_urb_for_dma(hcd, urb, mem_flags);
+
+ /* Control packets over dma */
+ if (urb->setup_dma)
+ dma_sync_single_for_device(hcd->self.controller,
+ urb->setup_dma, sizeof(struct usb_ctrlrequest),
+ DMA_TO_DEVICE);
+
+ /* urb buffers over dma */
+ if (urb->transfer_dma) {
+ enum dma_data_direction dir;
+ dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+
+ dma_sync_single_for_device(hcd->self.controller,
+ urb->transfer_dma, urb->transfer_buffer_length, dir);
}
- if (i == 2)
- retval = -ETIMEDOUT;
-
- /*
- * Clear Connect Status Change bit if it's set.
- * We can't clear PORT_PEC. It will also cause PORT_PE to be cleared.
- */
- if (temp & PORT_CSC)
- ehci_writel(ehci, PORT_CSC, portsc_reg);
-
- /*
- * Write to clear any interrupt status bits that might be set
- * during port reset.
- */
- temp = ehci_readl(ehci, &ehci->regs->status);
- ehci_writel(ehci, temp, &ehci->regs->status);
-
- /* restore original interrupt enable bits */
- ehci_writel(ehci, saved_usbintr, &ehci->regs->intr_enable);
- return retval;
+
+ if (ret)
+ free_align_buffer(urb);
+
+ return ret;
}
-static irqreturn_t tegra_ehci_irq (struct usb_hcd *hcd)
+static void tegra_ehci_unmap_urb_for_dma(struct usb_hcd *hcd,
+ struct urb *urb)
+{
+
+ if (urb->transfer_dma) {
+ enum dma_data_direction dir;
+ dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+ if (dir == DMA_FROM_DEVICE)
+ dma_sync_single_for_cpu(hcd->self.controller,
+ urb->transfer_dma, urb->transfer_buffer_length,
+ DMA_FROM_DEVICE);
+ }
+
+ usb_hcd_unmap_urb_for_dma(hcd, urb);
+ free_align_buffer(urb);
+}
+
+static irqreturn_t tegra_ehci_irq(struct usb_hcd *hcd)
{
- struct ehci_hcd *ehci = hcd_to_ehci (hcd);
- struct ehci_regs __iomem *hw = ehci->regs;
struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
- u32 val;
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
irqreturn_t irq_status;
bool pmc_remote_wakeup = false;
- /* Fence read for coherency of AHB master intiated writes */
- if (tegra->phy->instance == 0)
- readb(IO_ADDRESS(IO_PPCS_PHYS + USB1_PREFETCH_ID));
- else if (tegra->phy->instance == 1)
- readb(IO_ADDRESS(IO_PPCS_PHYS + USB2_PREFETCH_ID));
- else if (tegra->phy->instance == 2)
- readb(IO_ADDRESS(IO_PPCS_PHYS + USB3_PREFETCH_ID));
-
- if ((tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP) &&
- (tegra->ehci->has_hostpc)) {
- /* check if there is any remote wake event */
- if (tegra_usb_phy_is_remotewake_detected(tegra->phy)) {
- pmc_remote_wakeup = true;
- spin_lock (&ehci->lock);
- usb_hcd_resume_root_hub(hcd);
- spin_unlock (&ehci->lock);
- }
- }
- if (tegra->phy->hotplug) {
- spin_lock(&ehci->lock);
- val = readl(hcd->regs + TEGRA_USB_SUSP_CTRL_OFFSET);
- if ((val & TEGRA_USB_PHY_CLK_VALID_INT_STS)) {
- val &= ~TEGRA_USB_PHY_CLK_VALID_INT_ENB |
- TEGRA_USB_PHY_CLK_VALID_INT_STS;
- writel(val , (hcd->regs + TEGRA_USB_SUSP_CTRL_OFFSET));
-
- val = readl(&hw->status);
- if (!(val & STS_PCD)) {
- spin_unlock(&ehci->lock);
- return 0;
- }
- val = readl(hcd->regs + TEGRA_USB_PORTSC1_OFFSET);
- val &= ~(TEGRA_USB_PORTSC1_WKCN | PORT_RWC_BITS);
- writel(val , (hcd->regs + TEGRA_USB_PORTSC1_OFFSET));
- }
+ spin_lock(&ehci->lock);
+ irq_status = tegra_usb_phy_irq(tegra->phy);
+ if (irq_status == IRQ_NONE) {
spin_unlock(&ehci->lock);
+ return irq_status;
+ }
+ if (tegra_usb_phy_remote_wakeup(tegra->phy)) {
+ ehci_info(ehci, "remote wakeup detected\n");
+ pmc_remote_wakeup = true;
+ usb_hcd_resume_root_hub(hcd);
}
+ spin_unlock(&ehci->lock);
+
+ EHCI_DBG("%s() cmd = 0x%x, int_sts = 0x%x, portsc = 0x%x\n", __func__,
+ ehci_readl(ehci, &ehci->regs->command),
+ ehci_readl(ehci, &ehci->regs->status),
+ ehci_readl(ehci, &ehci->regs->port_status[0]));
irq_status = ehci_irq(hcd);
@@ -218,61 +184,37 @@ static irqreturn_t tegra_ehci_irq (struct usb_hcd *hcd)
if (ehci->controller_remote_wakeup) {
ehci->controller_remote_wakeup = false;
- /* disable interrupts */
- ehci_writel(ehci, 0, &ehci->regs->intr_enable);
- tegra_usb_phy_preresume(tegra->phy, true);
+ tegra_usb_phy_pre_resume(tegra->phy, true);
tegra->port_resuming = 1;
}
return irq_status;
}
+
static int tegra_ehci_hub_control(
struct usb_hcd *hcd,
- u16 typeReq,
- u16 wValue,
- u16 wIndex,
- char *buf,
- u16 wLength
+ u16 typeReq,
+ u16 wValue,
+ u16 wIndex,
+ char *buf,
+ u16 wLength
)
{
- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
- int ports = HCS_N_PORTS(ehci->hcs_params);
- u32 temp, status, cmd_run;
- u32 __iomem *status_reg;
- u32 usbsts_reg;
-
+ struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
unsigned long flags;
- int retval = 0;
- unsigned selector;
- struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
- bool hsic = false;
+ int retval = 0;
+ u32 __iomem *status_reg;
- mutex_lock(&tegra->tegra_ehci_hcd_mutex);
- if (!tegra->host_resumed) {
+ if (!tegra_usb_phy_hw_accessible(tegra->phy)) {
if (buf)
- memset (buf, 0, wLength);
- mutex_unlock(&tegra->tegra_ehci_hcd_mutex);
+ memset(buf, 0, wLength);
return retval;
}
- hsic = (tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_HSIC);
-
- status_reg = &ehci->regs->port_status[(wIndex & 0xff) - 1];
-
- spin_lock_irqsave(&ehci->lock, flags);
-
- /*
- * In ehci_hub_control() for USB_PORT_FEAT_ENABLE clears the other bits
- * that are write on clear, by writing back the register read value, so
- * USB_PORT_FEAT_ENABLE is handled by masking the set on clear bits
- */
- if (typeReq == ClearPortFeature && wValue == USB_PORT_FEAT_ENABLE) {
- temp = ehci_readl(ehci, status_reg) & ~PORT_RWC_BITS;
- ehci_writel(ehci, temp & ~PORT_PE, status_reg);
- goto done;
- } else if (typeReq == GetPortStatus) {
- temp = ehci_readl(ehci, status_reg);
- /* check port is in resume state */
+ /* Do tegra phy specific actions based on the type request */
+ switch (typeReq) {
+ case GetPortStatus:
if (tegra->port_resuming) {
int delay = ehci->reset_done[wIndex-1] - jiffies;
/* Sometimes it seems we get called too soon... In that case, wait.*/
@@ -280,501 +222,79 @@ static int tegra_ehci_hub_control(
ehci_dbg(ehci, "GetPortStatus called too soon, waiting %dms...\n", delay);
mdelay(jiffies_to_msecs(delay));
}
+ status_reg = &ehci->regs->port_status[(wIndex & 0xff) - 1];
/* Ensure the port PORT_SUSPEND and PORT_RESUME has cleared */
if (handshake(ehci, status_reg, (PORT_SUSPEND | PORT_RESUME), 0, 25000)) {
- pr_err("%s: timeout waiting for SUSPEND to clear\n", __func__);
+ EHCI_DBG("%s: timeout waiting for SUSPEND to clear\n", __func__);
}
+ tegra_usb_phy_post_resume(tegra->phy);
tegra->port_resuming = 0;
- tegra_usb_phy_postresume(tegra->phy, false);
- if (tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP) {
+ /* If run bit is not set by now enable it */
+ if (ehci->command & CMD_RUN) {
ehci->command |= CMD_RUN;
- cmd_run = ehci_readl(ehci, &ehci->regs->command);
- cmd_run |= CMD_RUN;
- /*
- * ehci run bit is disabled to avoid SOF.
- * 2LS WAR is executed by now enable the run bit.
- */
- ehci_writel(ehci, cmd_run, &ehci->regs->command);
- /* Now we can safely re-enable irqs */
- ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable);
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
}
+ /* Now we can safely re-enable irqs */
+ ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable);
}
-
- } else if (typeReq == SetPortFeature && wValue == USB_PORT_FEAT_SUSPEND) {
- temp = ehci_readl(ehci, status_reg);
- if ((temp & PORT_PE) == 0 || (temp & PORT_RESET) != 0) {
- retval = -EPIPE;
- goto done;
- }
-
- temp &= ~PORT_WKCONN_E;
- temp |= PORT_WKDISC_E | PORT_WKOC_E;
- ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
-
- /* Need a 4ms delay before the controller goes to suspend */
- mdelay(4);
-
- /*
- * If a transaction is in progress, there may be a delay in
- * suspending the port. Poll until the port is suspended.
- */
- if (handshake(ehci, status_reg, PORT_SUSPEND,
- PORT_SUSPEND, 5000))
- pr_err("%s: timeout waiting for SUSPEND\n", __func__);
-
- set_bit((wIndex & 0xff) - 1, &ehci->suspended_ports);
- /*
- * If RUN bit is disabled interrupt is not generated after suspend.
- * This change on T20 will allow ASE interrupt generated after suspend
- * which will unlink the qheads.
- */
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- if (tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP) {
- /* Disable RUN bit. */
- ehci->command &= ~CMD_RUN;
- cmd_run = ehci_readl(ehci, &ehci->regs->command);
- cmd_run &= ~CMD_RUN;
- ehci_writel(ehci, cmd_run, &ehci->regs->command);
- if (handshake (ehci, &ehci->regs->status,
- STS_HALT, STS_HALT, 16 * 125))
- pr_err("%s() timeout waiting for STS_HALT\n", __func__);
+ break;
+ case ClearPortFeature:
+ if (wValue == USB_PORT_FEAT_SUSPEND) {
+ tegra_usb_phy_pre_resume(tegra->phy, false);
+ tegra->port_resuming = 1;
+ } else if (wValue == USB_PORT_FEAT_ENABLE) {
+ u32 temp;
+ temp = ehci_readl(ehci, &ehci->regs->port_status[0]) & ~PORT_RWC_BITS;
+ ehci_writel(ehci, temp & ~PORT_PE, &ehci->regs->port_status[0]);
+ return retval;
}
-#endif
- tegra_usb_phy_postsuspend(tegra->phy, false);
-
- goto done;
- }
-
- /* For USB1 port we need to issue Port Reset twice internally */
- if (tegra->phy->instance == 0 &&
- (typeReq == SetPortFeature && wValue == USB_PORT_FEAT_RESET)) {
- spin_unlock_irqrestore(&ehci->lock, flags);
- mutex_unlock(&tegra->tegra_ehci_hcd_mutex);
- return tegra_ehci_internal_port_reset(ehci, status_reg);
+ break;
}
- /*
- * Tegra host controller will time the resume operation to clear the bit
- * when the port control state switches to HS or FS Idle. This behavior
- * is different from EHCI where the host controller driver is required
- * to set this bit to a zero after the resume duration is timed in the
- * driver.
- */
- else if (typeReq == ClearPortFeature &&
- wValue == USB_PORT_FEAT_SUSPEND) {
- temp = ehci_readl(ehci, status_reg);
- if ((temp & PORT_RESET) || !(temp & PORT_PE)) {
- retval = -EPIPE;
- goto done;
- }
-
- if (!(temp & PORT_SUSPEND))
- goto done;
-
- tegra->port_resuming = 1;
-
- if (tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP) {
- /* disable interrupts */
- ehci_writel(ehci, 0, &ehci->regs->intr_enable);
- /* Disable RUN bit. */
- ehci->command &= ~CMD_RUN;
- cmd_run = ehci_readl(ehci, &ehci->regs->command);
- cmd_run &= ~CMD_RUN;
- ehci_writel(ehci, cmd_run, &ehci->regs->command);
- if (handshake (ehci, &ehci->regs->status,
- STS_HALT, STS_HALT, 16 * 125))
- pr_err("%s() timeout waiting for STS_HALT\n", __func__);
- }
-
- /* Disable disconnect detection during port resume */
- tegra_usb_phy_preresume(tegra->phy, false);
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- if (tegra->phy->usb_phy_type != TEGRA_USB_PHY_TYPE_UTMIP) {
-#endif
- ehci_dbg(ehci, "%s:USBSTS = 0x%x", __func__,
- ehci_readl(ehci, &ehci->regs->status));
- usbsts_reg = ehci_readl(ehci, &ehci->regs->status);
- ehci_writel(ehci, usbsts_reg, &ehci->regs->status);
- usbsts_reg = ehci_readl(ehci, &ehci->regs->status);
- udelay(20);
-
- if (handshake(ehci, &ehci->regs->status, STS_SRI, STS_SRI, 2000))
- pr_err("%s: timeout set for STS_SRI\n", __func__);
-
- usbsts_reg = ehci_readl(ehci, &ehci->regs->status);
- ehci_writel(ehci, usbsts_reg, &ehci->regs->status);
-
- if (handshake(ehci, &ehci->regs->status, STS_SRI, 0, 2000))
- pr_err("%s: timeout clear STS_SRI\n", __func__);
-
- if (handshake(ehci, &ehci->regs->status, STS_SRI, STS_SRI, 2000))
- pr_err("%s: timeout set STS_SRI\n", __func__);
-
- udelay(20);
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- }
-#endif
- temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
- /* start resume signaling */
- ehci_writel(ehci, temp | PORT_RESUME, status_reg);
-
- ehci->reset_done[wIndex-1] = jiffies + msecs_to_jiffies(25);
- /* whoever resumes must GetPortStatus to complete it!! */
- goto done;
- }
+ /* handle ehci hub control request */
+ retval = ehci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);
- /* Handle port reset here */
- if ((hsic) && (typeReq == SetPortFeature) &&
- ((wValue == USB_PORT_FEAT_RESET) || (wValue == USB_PORT_FEAT_POWER))) {
- selector = wIndex >> 8;
- wIndex &= 0xff;
- if (!wIndex || wIndex > ports) {
- retval = -EPIPE;
- goto done;
- }
- wIndex--;
- status = 0;
- temp = ehci_readl(ehci, status_reg);
- if (temp & PORT_OWNER)
- goto done;
- temp &= ~PORT_RWC_BITS;
-
- switch (wValue) {
- case USB_PORT_FEAT_RESET:
- {
- if (temp & PORT_RESUME) {
- retval = -EPIPE;
- goto done;
- }
- /* 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
- && !ehci_is_TDI(ehci) && PORT_USB11 (temp)) {
- ehci_dbg (ehci, "port %d low speed --> companion\n", wIndex + 1);
- temp |= PORT_OWNER;
- ehci_writel(ehci, temp, status_reg);
- } else {
- ehci_vdbg(ehci, "port %d reset\n", wIndex + 1);
- temp &= ~PORT_PE;
- /*
- * caller must wait, then call GetPortStatus
- * usb 2.0 spec says 50 ms resets on root
- */
- ehci->reset_done[wIndex] = jiffies + msecs_to_jiffies(50);
- ehci_writel(ehci, temp, status_reg);
- if (hsic && (wIndex == 0))
+ /* do tegra phy specific actions based on the type request */
+ if (!retval) {
+ switch (typeReq) {
+ case SetPortFeature:
+ if (wValue == USB_PORT_FEAT_SUSPEND) {
+ /* Need a 4ms delay for controller to suspend */
+ mdelay(4);
+ tegra_usb_phy_post_suspend(tegra->phy);
+ } else if (wValue == USB_PORT_FEAT_RESET) {
+ if (wIndex == 1)
tegra_usb_phy_bus_reset(tegra->phy);
+ } else if (wValue == USB_PORT_FEAT_POWER) {
+ if (wIndex == 1)
+ tegra_usb_phy_port_power(tegra->phy);
}
-
break;
- }
- case USB_PORT_FEAT_POWER:
- {
- if (HCS_PPC(ehci->hcs_params))
- ehci_writel(ehci, temp | PORT_POWER, status_reg);
- if (hsic && (wIndex == 0))
- tegra_usb_phy_bus_connect(tegra->phy);
+ case ClearPortFeature:
+ if (wValue == USB_PORT_FEAT_SUSPEND) {
+ /* tegra USB controller needs 25 ms to resume the port */
+ ehci->reset_done[wIndex-1] = jiffies + msecs_to_jiffies(25);
+ }
break;
}
- }
- goto done;
}
- spin_unlock_irqrestore(&ehci->lock, flags);
-
- /* Handle the hub control events here */
- retval = ehci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);
- mutex_unlock(&tegra->tegra_ehci_hcd_mutex);
- return retval;
-done:
- spin_unlock_irqrestore(&ehci->lock, flags);
- mutex_unlock(&tegra->tegra_ehci_hcd_mutex);
return retval;
}
-#ifdef CONFIG_PM
-static void tegra_ehci_restart(struct usb_hcd *hcd, bool is_dpd)
-{
- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
- struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
- unsigned int temp;
-
- ehci->controller_resets_phy = 0;
- tegra_ehci_pre_reset(tegra->phy, false);
- ehci_reset(ehci);
- tegra_ehci_post_reset(tegra->phy, false);
-
- if (tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_NULL_ULPI)
- ehci->controller_resets_phy = 1;
-
- /* setup the frame list and Async q heads */
- ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);
- ehci_writel(ehci, (u32)ehci->async->qh_dma, &ehci->regs->async_next);
- /* setup the command register and set the controller in RUN mode */
- ehci->command &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- /* dont start RS here for HSIC, it will be set by bus_reset */
- if (tegra->phy->usb_phy_type != TEGRA_USB_PHY_TYPE_HSIC)
-#endif
- ehci->command |= CMD_RUN;
- ehci_writel(ehci, ehci->command, &ehci->regs->command);
-
- /* Enable the root Port Power */
- if (HCS_PPC(ehci->hcs_params)) {
- temp = ehci_readl(ehci, &ehci->regs->port_status[0]);
- ehci_writel(ehci, temp | PORT_POWER, &ehci->regs->port_status[0]);
- }
-
- down_write(&ehci_cf_port_reset_rwsem);
- if(is_dpd)
- hcd->state = HC_STATE_SUSPENDED;
- else
- hcd->state = HC_STATE_RUNNING;
- ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
- /* flush posted writes */
- ehci_readl(ehci, &ehci->regs->command);
- up_write(&ehci_cf_port_reset_rwsem);
-
- /* Turn On Interrupts */
- ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable);
-}
-
-static int tegra_usb_suspend(struct usb_hcd *hcd, bool is_dpd)
-{
- struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
- struct ehci_regs __iomem *hw = tegra->ehci->regs;
- unsigned long flags;
- int hsic = 0;
-
- hsic = (tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_HSIC);
-
- spin_lock_irqsave(&tegra->ehci->lock, flags);
-
- if (tegra->ehci->has_hostpc)
- tegra->port_speed = (readl(hcd->regs + HOSTPC_REG_OFFSET) >> 25) & 0x3;
- else
- tegra->port_speed = (readl(&hw->port_status[0]) >> 26) & 0x3;
- ehci_halt(tegra->ehci);
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- if (tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP) {
- /*
- * Ehci run bit is disabled by now read this into command variable
- * so that bus resume will not enable run bit immedialty.
- * this is required for 2LS WAR on UTMIP interface.
- */
- tegra->ehci->command = ehci_readl(tegra->ehci,
- &tegra->ehci->regs->command);
- }
-#endif
-
- spin_unlock_irqrestore(&tegra->ehci->lock, flags);
-
- tegra_ehci_power_down(hcd, is_dpd);
- return 0;
-}
-
-static int tegra_usb_resume(struct usb_hcd *hcd, bool is_dpd)
-{
- struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
- struct ehci_regs __iomem *hw = ehci->regs;
- unsigned long val;
- bool hsic;
- bool null_ulpi;
- bool utmip_remote_wakeup = false;
-
- null_ulpi = (tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_NULL_ULPI);
- hsic = (tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_HSIC);
-
- tegra_ehci_power_up(hcd, is_dpd);
- set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-
- if ((tegra->port_speed > TEGRA_USB_PHY_PORT_SPEED_HIGH) || (hsic) ||
- (null_ulpi))
- goto restart;
-
- /* Force the phy to keep data lines in suspend state */
- tegra_ehci_phy_restore_start(tegra->phy, tegra->port_speed);
-
- if (tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP) {
- ehci_reset(ehci);
- }
-
- /* Enable host mode */
- tdi_reset(ehci);
-
- if ((tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP) &&
- (tegra->ehci->has_hostpc)) {
- val = readl(hcd->regs + HOSTPC_REG_OFFSET);
- val &= ~HOSTPC1_DEVLC_PTS(~0);
- val |= HOSTPC1_DEVLC_STS;
- writel(val, hcd->regs + HOSTPC_REG_OFFSET);
- }
-
- /* Enable Port Power */
- val = readl(&hw->port_status[0]);
- val |= PORT_POWER;
- writel(val, &hw->port_status[0]);
- udelay(10);
-
- if ((tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP) &&
- (tegra->ehci->has_hostpc) && (tegra->phy->remote_wakeup)) {
- utmip_remote_wakeup = true;
- }
-
- /* Check if the phy resume from LP0. When the phy resume from LP0
- * USB register will be reset. */
- if (!readl(&hw->async_next)) {
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- /* Start the controller */
- val = readl(&hw->command);
- writel((val | CMD_RUN), &hw->command);
-#endif
- /* Program the field PTC based on the saved speed mode */
- val = readl(&hw->port_status[0]);
- val &= ~PORT_TEST(~0);
- if (tegra->port_speed == TEGRA_USB_PHY_PORT_SPEED_HIGH)
- val |= PORT_TEST_FORCE;
- else if (tegra->port_speed == TEGRA_USB_PHY_PORT_SPEED_FULL)
- val |= PORT_TEST(6);
- else if (tegra->port_speed == TEGRA_USB_PHY_PORT_SPEED_LOW)
- val |= PORT_TEST(7);
- writel(val, &hw->port_status[0]);
- udelay(10);
-
- /* Disable test mode by setting PTC field to NORMAL_OP */
- val = readl(&hw->port_status[0]);
- val &= ~PORT_TEST(~0);
- writel(val, &hw->port_status[0]);
- udelay(10);
- }
-
- /* Poll until CCS is enabled */
- if (handshake(ehci, &hw->port_status[0], PORT_CONNECT,
- PORT_CONNECT, 2000)) {
- pr_err("%s: timeout waiting for PORT_CONNECT\n", __func__);
- goto restart;
- }
-
- /* Poll until PE is enabled */
- if (handshake(ehci, &hw->port_status[0], PORT_PE,
- PORT_PE, 2000)) {
- pr_err("%s: timeout waiting for USB_PORTSC1_PE\n", __func__);
- goto restart;
- }
-
- /* Clear the PCI status, to avoid an interrupt taken upon resume */
- val = readl(&hw->status);
- val |= STS_PCD;
- writel(val, &hw->status);
-
- /* Put controller in suspend mode by writing 1 to SUSP bit of PORTSC */
- val = readl(&hw->port_status[0]);
- if ((val & PORT_POWER) && (val & PORT_PE)) {
- val |= PORT_SUSPEND;
- writel(val, &hw->port_status[0]);
-
- /* Need a 4ms delay before the controller goes to suspend */
- mdelay(4);
-
- /* Wait until port suspend completes */
- if (handshake(ehci, &hw->port_status[0], PORT_SUSPEND,
- PORT_SUSPEND, 1000)) {
- pr_err("%s: timeout waiting for PORT_SUSPEND\n",
- __func__);
- goto restart;
- }
- }
-
- tegra_ehci_phy_restore_end(tegra->phy);
- if (utmip_remote_wakeup) {
- ehci->command |= CMD_RUN;
- ehci_writel(ehci, ehci->command, &ehci->regs->command);
- }
- return 0;
-
-restart:
- if (null_ulpi) {
- bool LP0 = !readl(&hw->async_next);
-
- if (LP0) {
- static int cnt = 1;
-
- pr_info("LP0 restart %d\n", cnt++);
- tegra_ehci_phy_restore_start(tegra->phy,
- tegra->port_speed);
- }
-
- val = readl(&hw->port_status[0]);
- if (!((val & PORT_POWER) && (val & PORT_PE))) {
- tegra_ehci_restart(hcd, is_dpd);
- }
-
- if (LP0)
- tegra_ehci_phy_restore_end(tegra->phy);
-
- return 0;
- }
-
- if ((tegra->port_speed <= TEGRA_USB_PHY_PORT_SPEED_HIGH) && (!hsic))
- tegra_ehci_phy_restore_end(tegra->phy);
- if (hsic) {
- val = readl(&hw->port_status[0]);
- if (!((val & PORT_POWER) && (val & PORT_PE)))
- tegra_ehci_restart(hcd, false);
-
- tegra_usb_phy_bus_idle(tegra->phy);
- if (!tegra_usb_phy_is_device_connected(tegra->phy))
- pr_err("%s: no hsic device conenction\n", __func__);
- } else {
- tegra_ehci_restart(hcd, false);
- }
-
- return 0;
-}
-#endif
-
-/*
- * Disable PHY clock valid interrupts and wait for the interrupt handler to
- * finish.
- *
- * Requires a lock on tegra_ehci_hcd_mutex
- * Must not be called with a lock on ehci->lock
- */
-static void tegra_ehci_disable_phy_interrupt(struct usb_hcd *hcd) {
- struct tegra_ehci_hcd *tegra;
- u32 val;
- if (hcd->irq >= 0) {
- tegra = dev_get_drvdata(hcd->self.controller);
- if (tegra->phy->hotplug) {
- /* Disable PHY clock valid interrupts */
- val = readl(hcd->regs + TEGRA_USB_SUSP_CTRL_OFFSET);
- val &= ~TEGRA_USB_PHY_CLK_VALID_INT_ENB;
- writel(val , (hcd->regs + TEGRA_USB_SUSP_CTRL_OFFSET));
- }
- /* Wait for the interrupt handler to finish */
- synchronize_irq(hcd->irq);
- }
-}
-
static void tegra_ehci_shutdown(struct usb_hcd *hcd)
{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
-
- mutex_lock(&tegra->tegra_ehci_hcd_mutex);
- tegra_ehci_disable_phy_interrupt(hcd);
- /* ehci_shutdown touches the USB controller registers, make sure
- * controller has clocks to it */
- if (!tegra->host_resumed)
- tegra_ehci_power_up(hcd, false);
-
- ehci_shutdown(hcd);
-
- /* we are ready to shut down, powerdown the phy */
- tegra_ehci_power_down(hcd, false);
- mutex_unlock(&tegra->tegra_ehci_hcd_mutex);
+ mutex_lock(&tegra->sync_lock);
+ del_timer_sync(&ehci->watchdog);
+ del_timer_sync(&ehci->iaa_watchdog);
+ if (tegra_usb_phy_hw_accessible(tegra->phy)) {
+ spin_lock_irq(&ehci->lock);
+ ehci_silence_controller(ehci);
+ spin_unlock_irq(&ehci->lock);
+ }
+ mutex_unlock(&tegra->sync_lock);
}
static int tegra_ehci_setup(struct usb_hcd *hcd)
@@ -786,24 +306,18 @@ static int tegra_ehci_setup(struct usb_hcd *hcd)
/* EHCI registers start at offset 0x100 */
ehci->caps = hcd->regs + 0x100;
ehci->regs = hcd->regs + 0x100 +
- HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase));
+ HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase));
dbg_hcs_params(ehci, "reset");
dbg_hcc_params(ehci, "reset");
/* cache this readonly data; minimize chip reads */
ehci->hcs_params = readl(&ehci->caps->hcs_params);
+ ehci->has_hostpc = tegra_usb_phy_has_hostpc(tegra->phy) ? 1 : 0;
+ ehci->broken_hostpc_phcd = true;
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- ehci->has_hostpc = 1;
-#endif
hcd->has_tt = 1;
- if (tegra->phy->usb_phy_type != TEGRA_USB_PHY_TYPE_NULL_ULPI) {
- ehci_reset(ehci);
- tegra_ehci_post_reset(tegra->phy, false);
- }
-
retval = ehci_halt(ehci);
if (retval)
return retval;
@@ -815,242 +329,49 @@ static int tegra_ehci_setup(struct usb_hcd *hcd)
ehci->sbrn = 0x20;
ehci->controller_remote_wakeup = false;
-
- if (tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_NULL_ULPI) {
- tegra_ehci_pre_reset(tegra->phy, false);
- ehci_reset(ehci);
- tegra_ehci_post_reset(tegra->phy, false);
-
- /*
- * Resetting the controller has the side effect of resetting the PHY.
- * So, never reset the controller after the calling
- * tegra_ehci_reinit API.
- */
- ehci->controller_resets_phy = 1;
- }
+ ehci_reset(ehci);
+ tegra_usb_phy_reset(tegra->phy);
ehci_port_power(ehci, 1);
return retval;
}
+
#ifdef CONFIG_PM
static int tegra_ehci_bus_suspend(struct usb_hcd *hcd)
{
struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
- int error_status = 0;
-
- mutex_lock(&tegra->tegra_ehci_hcd_mutex);
+ int err = 0;
+ EHCI_DBG("%s() BEGIN\n", __func__);
+ mutex_lock(&tegra->sync_lock);
tegra->bus_suspended_fail = false;
- tegra_ehci_disable_phy_interrupt(hcd);
- /* ehci_shutdown touches the USB controller registers, make sure
- * controller has clocks to it */
- if (!tegra->host_resumed)
- tegra_ehci_power_up(hcd, false);
- error_status = ehci_bus_suspend(hcd);
- if (error_status)
+ err = ehci_bus_suspend(hcd);
+ if (err)
tegra->bus_suspended_fail = true;
- if (!error_status && tegra->power_down_on_bus_suspend) {
- tegra_usb_suspend(hcd, false);
- tegra->bus_suspended = 1;
- }
- mutex_unlock(&tegra->tegra_ehci_hcd_mutex);
+ else
+ tegra_usb_phy_suspend(tegra->phy);
+ mutex_unlock(&tegra->sync_lock);
+ EHCI_DBG("%s() END\n", __func__);
- return error_status;
+ return err;
}
static int tegra_ehci_bus_resume(struct usb_hcd *hcd)
{
struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
- int ehci_bus_resumed;
+ int err = 0;
+ EHCI_DBG("%s() BEGIN\n", __func__);
- mutex_lock(&tegra->tegra_ehci_hcd_mutex);
- if (tegra->bus_suspended && tegra->power_down_on_bus_suspend) {
- tegra_usb_resume(hcd, false);
- tegra->bus_suspended = 0;
- }
+ mutex_lock(&tegra->sync_lock);
+ tegra_usb_phy_resume(tegra->phy);
+ err = ehci_bus_resume(hcd);
+ mutex_unlock(&tegra->sync_lock);
+ EHCI_DBG("%s() END\n", __func__);
- ehci_bus_resumed = ehci_bus_resume(hcd);
- mutex_unlock(&tegra->tegra_ehci_hcd_mutex);
- return ehci_bus_resumed;
+ return err;
}
#endif
-struct dma_aligned_buffer {
- void *kmalloc_ptr;
- void *old_xfer_buffer;
- u8 data[0];
-};
-
-static void free_dma_aligned_buffer(struct urb *urb)
-{
- struct dma_aligned_buffer *temp = container_of(urb->transfer_buffer,
- struct dma_aligned_buffer, data);
-
- if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER))
- return;
-
- if(usb_urb_dir_in(urb))
- memcpy(temp->old_xfer_buffer, temp->data,
- urb->transfer_buffer_length);
- urb->transfer_buffer = temp->old_xfer_buffer;
- kfree(temp->kmalloc_ptr);
- urb->transfer_flags &= ~URB_ALIGNED_TEMP_BUFFER;
-}
-
-static int alloc_dma_aligned_buffer(struct urb *urb, gfp_t mem_flags)
-{
- struct dma_aligned_buffer *temp, *kmalloc_ptr;
- size_t kmalloc_size;
-
- if (urb->num_sgs || urb->sg ||
- urb->transfer_buffer_length == 0 ||
- !((uintptr_t)urb->transfer_buffer & (TEGRA_USB_DMA_ALIGN - 1)))
- return 0;
-
- /* Allocate a buffer with enough padding for alignment */
- kmalloc_size = urb->transfer_buffer_length +
- sizeof(struct dma_aligned_buffer) + TEGRA_USB_DMA_ALIGN - 1;
-
- kmalloc_ptr = kmalloc(kmalloc_size, mem_flags);
- if (!kmalloc_ptr)
- return -ENOMEM;
-
- /* Position our struct dma_aligned_buffer such that data is aligned */
- temp = PTR_ALIGN(kmalloc_ptr + 1, TEGRA_USB_DMA_ALIGN) - 1;
- temp->kmalloc_ptr = kmalloc_ptr;
- temp->old_xfer_buffer = urb->transfer_buffer;
- if (!usb_urb_dir_in(urb))
- memcpy(temp->data, urb->transfer_buffer,
- urb->transfer_buffer_length);
- urb->transfer_buffer = temp->data;
- urb->transfer_flags |= URB_ALIGNED_TEMP_BUFFER;
-
- return 0;
-}
-
-static int tegra_ehci_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
- gfp_t mem_flags)
-{
- int ret;
-
- ret = alloc_dma_aligned_buffer(urb, mem_flags);
- if (ret)
- return ret;
-
- ret = usb_hcd_map_urb_for_dma(hcd, urb, mem_flags);
- if (ret)
- free_dma_aligned_buffer(urb);
-
- return ret;
-}
-
-static void tegra_ehci_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
-{
- struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
-
- /* Fence read for coherency of AHB master intiated writes */
- if (tegra->phy->instance == 0)
- readb(IO_ADDRESS(IO_PPCS_PHYS + USB1_PREFETCH_ID));
- else if (tegra->phy->instance == 1)
- readb(IO_ADDRESS(IO_PPCS_PHYS + USB2_PREFETCH_ID));
- else if (tegra->phy->instance == 2)
- readb(IO_ADDRESS(IO_PPCS_PHYS + USB3_PREFETCH_ID));
-
- usb_hcd_unmap_urb_for_dma(hcd, urb);
- free_dma_aligned_buffer(urb);
-}
-
-void clk_timer_callback(unsigned long data)
-{
- struct tegra_ehci_hcd *tegra = (struct tegra_ehci_hcd*) data;
- unsigned long flags;
-
- if (!timer_pending(&tegra->clk_timer)) {
- spin_lock_irqsave(&tegra->ehci->lock, flags);
- tegra->timer_event = 1;
- spin_unlock_irqrestore(&tegra->ehci->lock, flags);
- schedule_work(&tegra->clk_timer_work);
- }
-}
-
-static void clk_timer_work_handler(struct work_struct* clk_timer_work) {
- struct tegra_ehci_hcd *tegra = container_of(clk_timer_work,
- struct tegra_ehci_hcd, clk_timer_work);
- int ret;
- unsigned long flags;
- bool clock_enabled, timer_event;
-
- spin_lock_irqsave(&tegra->ehci->lock, flags);
- clock_enabled = tegra->clock_enabled;
- timer_event = tegra->timer_event;
- spin_unlock_irqrestore(&tegra->ehci->lock, flags);
-
- if (timer_event) {
- spin_lock_irqsave(&tegra->ehci->lock, flags);
- tegra->clock_enabled = 0;
- tegra->timer_event = 0;
- spin_unlock_irqrestore(&tegra->ehci->lock, flags);
- clk_disable(tegra->emc_clk);
- clk_disable(tegra->sclk_clk);
- return;
- }
-
- if ((!clock_enabled)) {
- ret = mod_timer(&tegra->clk_timer, jiffies + msecs_to_jiffies(2000));
- if (ret)
- pr_err("tegra_ehci_urb_enqueue timer modify failed \n");
- clk_enable(tegra->emc_clk);
- clk_enable(tegra->sclk_clk);
- spin_lock_irqsave(&tegra->ehci->lock, flags);
- tegra->clock_enabled = 1;
- spin_unlock_irqrestore(&tegra->ehci->lock, flags);
- } else {
- if (timer_pending(&tegra->clk_timer)) {
- mod_timer_pending (&tegra->clk_timer, jiffies
- + msecs_to_jiffies(2000));
- }
- }
-}
-
-static int tegra_ehci_urb_enqueue (
- struct usb_hcd *hcd,
- struct urb *urb,
- gfp_t mem_flags)
-{
- struct tegra_ehci_hcd *pdata;
- int xfertype;
- int transfer_buffer_length;
- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
- unsigned long flags;
- pdata = dev_get_drvdata(hcd->self.controller);
-
- xfertype = usb_endpoint_type(&urb->ep->desc);
- transfer_buffer_length = urb->transfer_buffer_length;
- spin_lock_irqsave(&ehci->lock,flags);
- /* Turn on the USB busy hints */
- switch (xfertype) {
- case USB_ENDPOINT_XFER_INT:
- if (transfer_buffer_length < 255) {
- /* Do nothing for interrupt buffers < 255 */
- } else {
- /* signal to set the busy hints */
- schedule_work(&pdata->clk_timer_work);
- }
- break;
- case USB_ENDPOINT_XFER_ISOC:
- case USB_ENDPOINT_XFER_BULK:
- /* signal to set the busy hints */
- schedule_work(&pdata->clk_timer_work);
- break;
- case USB_ENDPOINT_XFER_CONTROL:
- default:
- /* Do nothing special here */
- break;
- }
- spin_unlock_irqrestore(&ehci->lock,flags);
- return ehci_urb_enqueue(hcd, urb, mem_flags);
-}
-
static const struct hc_driver tegra_ehci_hc_driver = {
.description = hcd_name,
.product_desc = "Tegra EHCI Host Controller",
@@ -1060,9 +381,10 @@ static const struct hc_driver tegra_ehci_hc_driver = {
/* standard ehci functions */
.start = ehci_run,
.stop = ehci_stop,
+ .urb_enqueue = ehci_urb_enqueue,
.urb_dequeue = ehci_urb_dequeue,
.endpoint_disable = ehci_endpoint_disable,
- .endpoint_reset = ehci_endpoint_reset,
+ .endpoint_reset = ehci_endpoint_reset,
.get_frame_number = ehci_get_frame,
.hub_status_data = ehci_hub_status_data,
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
@@ -1076,10 +398,9 @@ static const struct hc_driver tegra_ehci_hc_driver = {
.map_urb_for_dma = tegra_ehci_map_urb_for_dma,
.unmap_urb_for_dma = tegra_ehci_unmap_urb_for_dma,
.hub_control = tegra_ehci_hub_control,
- .urb_enqueue = tegra_ehci_urb_enqueue,
#ifdef CONFIG_PM
- .bus_suspend = tegra_ehci_bus_suspend,
- .bus_resume = tegra_ehci_bus_resume,
+ .bus_suspend = tegra_ehci_bus_suspend,
+ .bus_resume = tegra_ehci_bus_resume,
#endif
};
@@ -1088,76 +409,30 @@ static int tegra_ehci_probe(struct platform_device *pdev)
struct resource *res;
struct usb_hcd *hcd;
struct tegra_ehci_hcd *tegra;
- struct tegra_ehci_platform_data *pdata;
int err = 0;
int irq;
- int instance = pdev->id;
- pdata = pdev->dev.platform_data;
- if (!pdata) {
- dev_err(&pdev->dev, "Platform data missing\n");
- return -EINVAL;
- }
-
- tegra = kzalloc(sizeof(struct tegra_ehci_hcd), GFP_KERNEL);
- if (!tegra)
+ tegra = devm_kzalloc(&pdev->dev, sizeof(struct tegra_ehci_hcd),
+ GFP_KERNEL);
+ if (!tegra) {
+ dev_err(&pdev->dev, "memory alloc failed\n");
return -ENOMEM;
+ }
- mutex_init(&tegra->tegra_ehci_hcd_mutex);
+ mutex_init(&tegra->sync_lock);
hcd = usb_create_hcd(&tegra_ehci_hc_driver, &pdev->dev,
dev_name(&pdev->dev));
if (!hcd) {
- dev_err(&pdev->dev, "Unable to create HCD\n");
- err = -ENOMEM;
- goto fail_hcd;
+ dev_err(&pdev->dev, "unable to create HCD\n");
+ return -ENOMEM;
}
platform_set_drvdata(pdev, tegra);
- tegra->default_enable = pdata->default_enable;
-
- tegra->clk = clk_get(&pdev->dev, NULL);
- if (IS_ERR(tegra->clk)) {
- dev_err(&pdev->dev, "Can't get ehci clock\n");
- err = PTR_ERR(tegra->clk);
- goto fail_clk;
- }
-
- err = clk_enable(tegra->clk);
- if (err)
- goto fail_clken;
-
-
- tegra->sclk_clk = clk_get(&pdev->dev, "sclk");
- if (IS_ERR(tegra->sclk_clk)) {
- dev_err(&pdev->dev, "Can't get sclk clock\n");
- err = PTR_ERR(tegra->sclk_clk);
- goto fail_sclk_clk;
- }
-
- clk_set_rate(tegra->sclk_clk, 80000000);
-
- tegra->emc_clk = clk_get(&pdev->dev, "emc");
- if (IS_ERR(tegra->emc_clk)) {
- dev_err(&pdev->dev, "Can't get emc clock\n");
- err = PTR_ERR(tegra->emc_clk);
- goto fail_emc_clk;
- }
- init_timer(&tegra->clk_timer);
- tegra->clk_timer.function = clk_timer_callback;
- tegra->clk_timer.data = (unsigned long) tegra;
-
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- /* Set DDR busy hints to 150MHz. For Tegra 2x SOC, DDR rate is half of EMC rate */
- clk_set_rate(tegra->emc_clk, 300000000);
-#else
- /* Set DDR busy hints to 100MHz. For Tegra 3x SOC DDR rate equals to EMC rate */
- clk_set_rate(tegra->emc_clk, 100000000);
-#endif
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
- dev_err(&pdev->dev, "Failed to get I/O memory\n");
+ dev_err(&pdev->dev, "failed to get I/O memory\n");
err = -ENXIO;
goto fail_io;
}
@@ -1165,179 +440,94 @@ static int tegra_ehci_probe(struct platform_device *pdev)
hcd->rsrc_len = resource_size(res);
hcd->regs = ioremap(res->start, resource_size(res));
if (!hcd->regs) {
- dev_err(&pdev->dev, "Failed to remap I/O memory\n");
+ dev_err(&pdev->dev, "failed to remap I/O memory\n");
err = -ENOMEM;
goto fail_io;
}
- INIT_WORK(&tegra->clk_timer_work, clk_timer_work_handler);
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "failed to get IRQ\n");
+ err = -ENODEV;
+ goto fail_irq;
+ }
+ set_irq_flags(irq, IRQF_VALID);
+ tegra->irq = irq;
- tegra->phy = tegra_usb_phy_open(instance, hcd->regs, pdata->phy_config,
- TEGRA_USB_PHY_MODE_HOST, pdata->phy_type);
+ tegra->phy = tegra_usb_phy_open(pdev);
if (IS_ERR(tegra->phy)) {
- dev_err(&pdev->dev, "Failed to open USB phy\n");
+ dev_err(&pdev->dev, "failed to open USB phy\n");
err = -ENXIO;
- goto fail_phy;
+ goto fail_irq;
}
- tegra->phy->hotplug = pdata->hotplug;
- err = tegra_usb_phy_power_on(tegra->phy, true);
+ err = tegra_usb_phy_power_on(tegra->phy);
if (err) {
- dev_err(&pdev->dev, "Failed to power on the phy\n");
- goto fail;
- }
-
- tegra->host_resumed = 1;
- tegra->power_down_on_bus_suspend = pdata->power_down_on_bus_suspend;
- tegra->ehci = hcd_to_ehci(hcd);
-
- irq = platform_get_irq(pdev, 0);
- if (!irq) {
- dev_err(&pdev->dev, "Failed to get IRQ\n");
- err = -ENODEV;
- goto fail;
+ dev_err(&pdev->dev, "failed to power on the phy\n");
+ goto fail_phy;
}
- set_irq_flags(irq, IRQF_VALID);
- tegra->irq = irq;
-#ifdef CONFIG_USB_OTG_UTILS
- if (pdata->operating_mode == TEGRA_USB_OTG) {
- tegra->transceiver = otg_get_transceiver();
- if (tegra->transceiver)
- otg_set_host(tegra->transceiver, &hcd->self);
+ err = tegra_usb_phy_init(tegra->phy);
+ if (err) {
+ dev_err(&pdev->dev, "failed to init the phy\n");
+ goto fail_phy;
}
-#endif
- err = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
+ err = usb_add_hcd(hcd, irq, IRQF_SHARED | IRQF_TRIGGER_HIGH);
if (err) {
- dev_err(&pdev->dev, "Failed to add USB HCD error = %d\n", err);
- goto fail;
+ dev_err(&pdev->dev, "Failed to add USB HCD, error=%d\n", err);
+ goto fail_phy;
}
err = enable_irq_wake(tegra->irq);
if (err < 0) {
dev_warn(&pdev->dev,
- "Couldn't enable USB host mode wakeup, irq=%d, "
- "error=%d\n", tegra->irq, err);
+ "Couldn't enable USB host mode wakeup, irq=%d, "
+ "error=%d\n", irq, err);
err = 0;
tegra->irq = 0;
}
- return err;
+ tegra->ehci = hcd_to_ehci(hcd);
-fail:
#ifdef CONFIG_USB_OTG_UTILS
- if (tegra->transceiver) {
- otg_set_host(tegra->transceiver, NULL);
- otg_put_transceiver(tegra->transceiver);
+ if (tegra_usb_phy_otg_supported(tegra->phy)) {
+ tegra->transceiver = otg_get_transceiver();
+ if (tegra->transceiver)
+ otg_set_host(tegra->transceiver, &hcd->self);
}
#endif
- tegra_usb_phy_close(tegra->phy);
+ return err;
+
fail_phy:
+ tegra_usb_phy_close(tegra->phy);
+fail_irq:
iounmap(hcd->regs);
fail_io:
- clk_disable(tegra->emc_clk);
- clk_put(tegra->emc_clk);
-fail_emc_clk:
- clk_disable(tegra->sclk_clk);
- clk_put(tegra->sclk_clk);
-fail_sclk_clk:
- clk_disable(tegra->clk);
-fail_clken:
- clk_put(tegra->clk);
-fail_clk:
usb_put_hcd(hcd);
-fail_hcd:
- kfree(tegra);
+
return err;
}
+
#ifdef CONFIG_PM
-static int tegra_ehci_resume_noirq(struct device *dev)
+static int tegra_ehci_resume(struct platform_device *pdev)
{
- struct platform_device *pdev = to_platform_device(dev);
struct tegra_ehci_hcd *tegra = platform_get_drvdata(pdev);
- mutex_lock(&tegra->tegra_ehci_hcd_mutex);
- if ((tegra->bus_suspended) && (tegra->power_down_on_bus_suspend)) {
- if (tegra->default_enable)
- clk_enable(tegra->clk);
- mutex_unlock(&tegra->tegra_ehci_hcd_mutex);
- return 0;
- }
-
- if (tegra->default_enable)
- clk_enable(tegra->clk);
-
- mutex_unlock(&tegra->tegra_ehci_hcd_mutex);
- return 0;
+ return tegra_usb_phy_power_on(tegra->phy);
}
-static int tegra_ehci_resume(struct device *dev)
+static int tegra_ehci_suspend(struct platform_device *pdev, pm_message_t state)
{
- struct platform_device *pdev = to_platform_device(dev);
struct tegra_ehci_hcd *tegra = platform_get_drvdata(pdev);
- struct usb_hcd *hcd = ehci_to_hcd(tegra->ehci);
- int ret;
-
- mutex_lock(&tegra->tegra_ehci_hcd_mutex);
- if ((tegra->bus_suspended) && (tegra->power_down_on_bus_suspend)) {
- mutex_unlock(&tegra->tegra_ehci_hcd_mutex);
- return 0;
- }
-
- ret = tegra_usb_resume(hcd, true);
- mutex_unlock(&tegra->tegra_ehci_hcd_mutex);
- return ret;
-}
-static int tegra_ehci_suspend(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct tegra_ehci_hcd *tegra = platform_get_drvdata(pdev);
- struct usb_hcd *hcd = ehci_to_hcd(tegra->ehci);
- int ret;
- u32 val;
-
- mutex_lock(&tegra->tegra_ehci_hcd_mutex);
- /* if bus suspend is failed means there is remote wakeup resume,
- then abort the PM suspend */
- if (tegra->bus_suspended_fail) {
- tegra->bus_suspended_fail = false;
- pr_err("%s: bus suspend failed, aborting driver suspend\n", __func__);
- mutex_unlock(&tegra->tegra_ehci_hcd_mutex);
+ /* bus suspend could have failed because of remote wakeup resume */
+ if (tegra->bus_suspended_fail)
return -EBUSY;
- }
- if (tegra->phy->hotplug) {
- /* Disable PHY clock valid interrupts while going into suspend*/
- val = readl(hcd->regs + TEGRA_USB_SUSP_CTRL_OFFSET);
- val &= ~TEGRA_USB_PHY_CLK_VALID_INT_ENB;
- writel(val , (hcd->regs + TEGRA_USB_SUSP_CTRL_OFFSET));
- }
-
- if ((tegra->bus_suspended) && (tegra->power_down_on_bus_suspend)) {
- if (tegra->default_enable)
- clk_disable(tegra->clk);
- mutex_unlock(&tegra->tegra_ehci_hcd_mutex);
- return 0;
- }
-
- if (time_before(jiffies, tegra->ehci->next_statechange))
- msleep(10);
-
- ret = tegra_usb_suspend(hcd, true);
- if (tegra->default_enable)
- clk_disable(tegra->clk);
- mutex_unlock(&tegra->tegra_ehci_hcd_mutex);
- return ret;
+ else
+ return tegra_usb_phy_power_off(tegra->phy);
}
-
-static struct dev_pm_ops tegra_ehci_dev_pm_ops = {
- .suspend = tegra_ehci_suspend,
- .resume = tegra_ehci_resume,
- .resume_noirq = tegra_ehci_resume_noirq,
-};
-
#endif
static int tegra_ehci_remove(struct platform_device *pdev)
@@ -1347,9 +537,6 @@ static int tegra_ehci_remove(struct platform_device *pdev)
if (tegra == NULL || hcd == NULL)
return -EINVAL;
- /* make sure controller is on as we will touch its registers */
- if (!tegra->host_resumed)
- tegra_ehci_power_up(hcd, true);
#ifdef CONFIG_USB_OTG_UTILS
if (tegra->transceiver) {
@@ -1358,30 +545,19 @@ static int tegra_ehci_remove(struct platform_device *pdev)
}
#endif
- /* Turn Off Interrupts */
- ehci_writel(tegra->ehci, 0, &tegra->ehci->regs->intr_enable);
- clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
if (tegra->irq)
disable_irq_wake(tegra->irq);
+
+ /* Make sure phy is powered ON to access USB register */
+ if(!tegra_usb_phy_hw_accessible(tegra->phy))
+ tegra_usb_phy_power_on(tegra->phy);
+
usb_remove_hcd(hcd);
usb_put_hcd(hcd);
- tegra_usb_phy_power_off(tegra->phy, true);
+ tegra_usb_phy_power_off(tegra->phy);
tegra_usb_phy_close(tegra->phy);
iounmap(hcd->regs);
- del_timer_sync(&tegra->clk_timer);
-
- clk_disable(tegra->clk);
- clk_put(tegra->clk);
-
- if (tegra->clock_enabled) {
- clk_disable(tegra->sclk_clk);
- clk_disable(tegra->emc_clk);
- }
- clk_put(tegra->sclk_clk);
- clk_put(tegra->emc_clk);
-
- kfree(tegra);
return 0;
}
@@ -1396,12 +572,13 @@ static void tegra_ehci_hcd_shutdown(struct platform_device *pdev)
static struct platform_driver tegra_ehci_driver = {
.probe = tegra_ehci_probe,
- .remove = tegra_ehci_remove,
+ .remove = tegra_ehci_remove,
.shutdown = tegra_ehci_hcd_shutdown,
- .driver = {
- .name = "tegra-ehci",
#ifdef CONFIG_PM
- .pm = &tegra_ehci_dev_pm_ops,
+ .suspend = tegra_ehci_suspend,
+ .resume = tegra_ehci_resume,
#endif
+ .driver = {
+ .name = driver_name,
}
};
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 509934ceb4a9..cfbdf32ec0b2 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -143,6 +143,7 @@ struct ehci_hcd { /* one per controller */
#ifdef CONFIG_USB_EHCI_TEGRA
unsigned controller_resets_phy:1;
unsigned controller_remote_wakeup:1;
+ unsigned broken_hostpc_phcd:1;
#endif
/* required for usb32 quirk */
diff --git a/drivers/usb/otg/tegra-otg.c b/drivers/usb/otg/tegra-otg.c
index 68d402afb25e..a5e85bf90d14 100644
--- a/drivers/usb/otg/tegra-otg.c
+++ b/drivers/usb/otg/tegra-otg.c
@@ -3,7 +3,7 @@
*
* OTG transceiver driver for Tegra UTMI phy
*
- * Copyright (C) 2010 NVIDIA Corp.
+ * Copyright (C) 2010-2012 NVIDIA CORPORATION. All rights reserved.
* Copyright (C) 2010 Google, Inc.
*
* This program is free software; you can redistribute it and/or modify it
@@ -24,7 +24,6 @@
#include <linux/usb.h>
#include <linux/usb/otg.h>
#include <linux/usb/gadget.h>
-#include <linux/usb/hcd.h>
#include <linux/platform_device.h>
#include <linux/platform_data/tegra_usb.h>
#include <linux/clk.h>
@@ -41,10 +40,8 @@
#define USB_VBUS_INT_EN (1 << 8)
#define USB_VBUS_INT_STATUS (1 << 9)
#define USB_VBUS_STATUS (1 << 10)
-#define USB_INTS (USB_VBUS_INT_STATUS | USB_ID_INT_STATUS)
-
-typedef void (*callback_t)(enum usb_otg_state to,
- enum usb_otg_state from, void *args);
+#define USB_INT_EN (USB_VBUS_INT_EN | USB_ID_INT_EN | \
+ USB_VBUS_WAKEUP_EN | USB_ID_PIN_WAKEUP_EN)
#ifdef DEBUG
#define DBG(stuff...) pr_info("tegra-otg: " stuff)
@@ -63,11 +60,11 @@ struct tegra_otg_data {
struct work_struct work;
unsigned int intr_reg_data;
bool clk_enabled;
- callback_t charger_cb;
- void *charger_cb_data;
-
bool interrupt_mode;
+ bool builtin_host;
+ bool suspended
};
+
static struct tegra_otg_data *tegra_clone;
static inline unsigned long otg_readl(struct tegra_otg_data *tegra,
@@ -82,20 +79,6 @@ static inline void otg_writel(struct tegra_otg_data *tegra, unsigned long val,
writel(val, tegra->regs + offset);
}
-static void tegra_otg_enable_clk(void)
-{
- if (!tegra_clone->clk_enabled)
- clk_enable(tegra_clone->clk);
- tegra_clone->clk_enabled = true;
-}
-
-static void tegra_otg_disable_clk(void)
-{
- if (tegra_clone->clk_enabled)
- clk_disable(tegra_clone->clk);
- tegra_clone->clk_enabled = false;
-}
-
static const char *tegra_state_name(enum usb_otg_state state)
{
switch (state) {
@@ -119,12 +102,13 @@ static unsigned long enable_interrupt(struct tegra_otg_data *tegra, bool en)
clk_enable(tegra->clk);
val = otg_readl(tegra, USB_PHY_WAKEUP);
if (en) {
- val |= (USB_VBUS_INT_EN | USB_VBUS_WAKEUP_EN);
- val |= (USB_ID_INT_EN | USB_ID_PIN_WAKEUP_EN);
- } else {
- val &= ~(USB_VBUS_INT_EN | USB_VBUS_WAKEUP_EN);
- val &= ~(USB_ID_INT_EN | USB_ID_PIN_WAKEUP_EN);
+ if (tegra->builtin_host)
+ val |= USB_INT_EN;
+ else
+ val = USB_VBUS_INT_EN | USB_VBUS_WAKEUP_EN | USB_ID_PIN_WAKEUP_EN;
}
+ else
+ val &= ~USB_INT_EN;
otg_writel(tegra, val, USB_PHY_WAKEUP);
/* Add delay to make sure register is updated */
udelay(1);
@@ -133,81 +117,70 @@ static unsigned long enable_interrupt(struct tegra_otg_data *tegra, bool en)
return val;
}
-static struct platform_device *
-tegra_usb_otg_host_register(struct platform_device *ehci_device,
- struct tegra_ehci_platform_data *pdata)
+static void tegra_start_host(struct tegra_otg_data *tegra)
{
- struct platform_device *pdev;
+ struct tegra_usb_otg_data *pdata = tegra->otg.dev->platform_data;
+ struct platform_device *pdev, *ehci_device = pdata->ehci_device;
void *platform_data;
int val;
+ DBG("%s(%d) Begin\n", __func__, __LINE__);
+
+ if (tegra->pdev)
+ return ;
+ /* prepare device structure for registering host*/
pdev = platform_device_alloc(ehci_device->name, ehci_device->id);
if (!pdev)
- return NULL;
+ return ;
val = platform_device_add_resources(pdev, ehci_device->resource,
ehci_device->num_resources);
if (val)
goto error;
- pdev->dev.dma_mask = ehci_device->dev.dma_mask;
+ pdev->dev.dma_mask = ehci_device->dev.dma_mask;
pdev->dev.coherent_dma_mask = ehci_device->dev.coherent_dma_mask;
- platform_data = kmalloc(sizeof(struct tegra_ehci_platform_data),
- GFP_KERNEL);
+ platform_data = kmalloc(sizeof(struct tegra_usb_platform_data), GFP_KERNEL);
if (!platform_data)
goto error;
- memcpy(platform_data, pdata, sizeof(struct tegra_ehci_platform_data));
+ memcpy(platform_data, pdata->ehci_pdata,
+ sizeof(struct tegra_usb_platform_data));
pdev->dev.platform_data = platform_data;
-
val = platform_device_add(pdev);
if (val)
goto error_add;
- return pdev;
+ tegra->pdev = pdev;
+ DBG("%s(%d) End\n", __func__, __LINE__);
+ return ;
error_add:
kfree(platform_data);
error:
pr_err("%s: failed to add the host controller device\n", __func__);
platform_device_put(pdev);
- return NULL;
+ tegra->pdev = NULL;
}
-static void tegra_usb_otg_host_unregister(struct platform_device *pdev)
+static void tegra_stop_host(struct tegra_otg_data *tegra)
{
- kfree(pdev->dev.platform_data);
- pdev->dev.platform_data = NULL;
- platform_device_unregister(pdev);
-}
+ struct platform_device *pdev = tegra->pdev;
-void tegra_start_host(struct tegra_otg_data *tegra)
-{
- struct tegra_otg_platform_data *pdata = tegra->otg.dev->platform_data;
- if (!tegra->pdev) {
- tegra->pdev = tegra_usb_otg_host_register(pdata->ehci_device,
- pdata->ehci_pdata);
- }
-}
+ DBG("%s(%d) Begin\n", __func__, __LINE__);
-void tegra_stop_host(struct tegra_otg_data *tegra)
-{
- if (tegra->pdev) {
- tegra_usb_otg_host_unregister(tegra->pdev);
+ if (pdev) {
+ /* unregister host from otg */
+ kfree(pdev->dev.platform_data);
+ pdev->dev.platform_data = NULL;
+ platform_device_unregister(pdev);
tegra->pdev = NULL;
}
-}
-int register_otg_callback(callback_t cb, void *args)
-{
- if (!tegra_clone)
- return -ENODEV;
- tegra_clone->charger_cb = cb;
- tegra_clone->charger_cb_data = args;
- return 0;
+ DBG("%s(%d) End\n", __func__, __LINE__);
}
-EXPORT_SYMBOL_GPL(register_otg_callback);
+
static void tegra_change_otg_state(struct tegra_otg_data *tegra,
enum usb_otg_state to)
@@ -228,9 +201,6 @@ static void tegra_change_otg_state(struct tegra_otg_data *tegra,
dev_info(tegra->otg.dev, "%s --> %s\n", tegra_state_name(from),
tegra_state_name(to));
- if (tegra->charger_cb)
- tegra->charger_cb(to, from, tegra->charger_cb_data);
-
if (from == OTG_STATE_A_SUSPEND) {
if (to == OTG_STATE_B_PERIPHERAL && otg->gadget)
usb_gadget_vbus_connect(otg->gadget);
@@ -256,10 +226,7 @@ static void irq_work(struct work_struct *work)
unsigned long flags;
unsigned long status;
- clk_enable(tegra->clk);
-
spin_lock_irqsave(&tegra->lock, flags);
-
status = tegra->int_status;
/* Debug prints */
@@ -274,7 +241,7 @@ static void irq_work(struct work_struct *work)
DBG("%s(%d) got vbus interrupt\n", __func__, __LINE__);
}
- if (!(status & USB_ID_STATUS))
+ if (!(status & USB_ID_STATUS) && (status & USB_ID_INT_EN))
to = OTG_STATE_A_HOST;
else if (status & USB_VBUS_STATUS && from != OTG_STATE_A_HOST)
to = OTG_STATE_B_PERIPHERAL;
@@ -283,8 +250,6 @@ static void irq_work(struct work_struct *work)
spin_unlock_irqrestore(&tegra->lock, flags);
tegra_change_otg_state(tegra, to);
- clk_disable(tegra->clk);
- tegra_otg_disable_clk();
}
static irqreturn_t tegra_otg_irq(int irq, void *data)
@@ -294,51 +259,52 @@ static irqreturn_t tegra_otg_irq(int irq, void *data)
unsigned long val;
spin_lock_irqsave(&tegra->lock, flags);
-
val = otg_readl(tegra, USB_PHY_WAKEUP);
+ DBG("%s(%d) interrupt val = 0x%x\n", __func__, __LINE__, val);
+
if (val & (USB_VBUS_INT_EN | USB_ID_INT_EN)) {
+ DBG("%s(%d) PHY_WAKEUP = 0x%x\n", __func__, __LINE__, val);
otg_writel(tegra, val, USB_PHY_WAKEUP);
if ((val & USB_ID_INT_STATUS) || (val & USB_VBUS_INT_STATUS)) {
tegra->int_status = val;
schedule_work(&tegra->work);
}
}
-
spin_unlock_irqrestore(&tegra->lock, flags);
return IRQ_HANDLED;
}
-void tegra_otg_check_vbus_detection(void)
-{
- tegra_otg_enable_clk();
-}
-EXPORT_SYMBOL(tegra_otg_check_vbus_detection);
static int tegra_otg_set_peripheral(struct otg_transceiver *otg,
struct usb_gadget *gadget)
{
struct tegra_otg_data *tegra;
unsigned long val;
+ DBG("%s(%d) BEGIN\n", __func__, __LINE__);
tegra = container_of(otg, struct tegra_otg_data, otg);
otg->gadget = gadget;
val = enable_interrupt(tegra, true);
- if ((val & USB_ID_STATUS) && (val & USB_VBUS_STATUS)) {
+ if ((val & USB_ID_STATUS) && (val & USB_VBUS_STATUS))
val |= USB_VBUS_INT_STATUS;
- } else if (!(val & USB_ID_STATUS)) {
- val |= USB_ID_INT_STATUS;
- } else {
- val &= ~(USB_ID_INT_STATUS | USB_VBUS_INT_STATUS);
+ else if (!(val & USB_ID_STATUS)) {
+ if(!tegra->builtin_host)
+ val &= ~USB_ID_INT_STATUS;
+ else
+ val |= USB_ID_INT_STATUS;
}
+ else
+ val &= ~(USB_ID_INT_STATUS | USB_VBUS_INT_STATUS);
if ((val & USB_ID_INT_STATUS) || (val & USB_VBUS_INT_STATUS)) {
tegra->int_status = val;
- schedule_work (&tegra->work);
+ schedule_work(&tegra->work);
}
+ DBG("%s(%d) END\n", __func__, __LINE__);
return 0;
}
@@ -347,6 +313,7 @@ static int tegra_otg_set_host(struct otg_transceiver *otg,
{
struct tegra_otg_data *tegra;
unsigned long val;
+ DBG("%s(%d) BEGIN\n", __func__, __LINE__);
tegra = container_of(otg, struct tegra_otg_data, otg);
otg->host = host;
@@ -354,11 +321,11 @@ static int tegra_otg_set_host(struct otg_transceiver *otg,
clk_enable(tegra->clk);
val = otg_readl(tegra, USB_PHY_WAKEUP);
val &= ~(USB_VBUS_INT_STATUS | USB_ID_INT_STATUS);
-
val |= (USB_ID_INT_EN | USB_ID_PIN_WAKEUP_EN);
otg_writel(tegra, val, USB_PHY_WAKEUP);
clk_disable(tegra->clk);
+ DBG("%s(%d) END\n", __func__, __LINE__);
return 0;
}
@@ -389,12 +356,9 @@ static ssize_t store_host_en(struct device *dev, struct device_attribute *attr,
struct platform_device *pdev = to_platform_device(dev);
struct tegra_otg_data *tegra = platform_get_drvdata(pdev);
unsigned long host;
- int err;
- err = kstrtoul(buf, 10, &host);
- if (err < 0) {
- return err;
- }
+ if (sscanf(buf, "%d", &host) != 1 || host < 0 || host > 1)
+ return -EINVAL;
if (host) {
enable_interrupt(tegra, false);
@@ -415,9 +379,8 @@ static DEVICE_ATTR(enable_host, 0644, show_host_en, store_host_en);
static int tegra_otg_probe(struct platform_device *pdev)
{
struct tegra_otg_data *tegra;
- struct tegra_otg_platform_data *otg_pdata;
- struct tegra_ehci_platform_data *ehci_pdata;
struct resource *res;
+ struct tegra_usb_otg_data *pdata = dev_get_platdata(&pdev->dev);
int err;
tegra = kzalloc(sizeof(struct tegra_otg_data), GFP_KERNEL);
@@ -425,8 +388,6 @@ static int tegra_otg_probe(struct platform_device *pdev)
return -ENOMEM;
tegra->otg.dev = &pdev->dev;
- otg_pdata = tegra->otg.dev->platform_data;
- ehci_pdata = otg_pdata->ehci_pdata;
tegra->otg.label = "tegra-otg";
tegra->otg.state = OTG_STATE_UNDEFINED;
tegra->otg.set_host = tegra_otg_set_host;
@@ -435,10 +396,14 @@ static int tegra_otg_probe(struct platform_device *pdev)
tegra->otg.set_power = tegra_otg_set_power;
spin_lock_init(&tegra->lock);
+ if (pdata) {
+ tegra->builtin_host = !pdata->ehci_pdata->builtin_host_disabled;
+ }
+
platform_set_drvdata(pdev, tegra);
tegra_clone = tegra;
- tegra->clk_enabled = false;
tegra->interrupt_mode = true;
+ tegra->suspended = false;
tegra->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(tegra->clk)) {
@@ -480,15 +445,23 @@ static int tegra_otg_probe(struct platform_device *pdev)
tegra->irq = res->start;
err = request_threaded_irq(tegra->irq, tegra_otg_irq,
NULL,
- IRQF_SHARED, "tegra-otg", tegra);
+ IRQF_SHARED | IRQF_TRIGGER_HIGH,
+ "tegra-otg", tegra);
if (err) {
dev_err(&pdev->dev, "Failed to register IRQ\n");
goto err_irq;
}
- INIT_WORK (&tegra->work, irq_work);
- if (!ehci_pdata->default_enable)
- clk_disable(tegra->clk);
+ err = enable_irq_wake(tegra->irq);
+ if (err < 0) {
+ dev_warn(&pdev->dev,
+ "Couldn't enable USB otg mode wakeup, irq=%d, error=%d\n",
+ tegra->irq, err);
+ err = 0;
+ }
+
+ INIT_WORK(&tegra->work, irq_work);
+
dev_info(&pdev->dev, "otg transceiver registered\n");
err = device_create_file(&pdev->dev, &dev_attr_enable_host);
@@ -497,6 +470,8 @@ static int tegra_otg_probe(struct platform_device *pdev)
goto err_irq;
}
+ clk_disable(tegra->clk);
+
return 0;
err_irq:
@@ -532,58 +507,67 @@ static int __exit tegra_otg_remove(struct platform_device *pdev)
static int tegra_otg_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
- struct tegra_otg_data *tegra_otg = platform_get_drvdata(pdev);
- struct otg_transceiver *otg = &tegra_otg->otg;
- enum usb_otg_state from = otg->state;
- unsigned int val;
-
- /* store the interupt enable for cable ID and VBUS */
- clk_enable(tegra_otg->clk);
- tegra_otg->intr_reg_data = readl(tegra_otg->regs + USB_PHY_WAKEUP);
- val = tegra_otg->intr_reg_data & ~(USB_ID_INT_EN | USB_VBUS_INT_EN);
- writel(val, (tegra_otg->regs + USB_PHY_WAKEUP));
- clk_disable(tegra_otg->clk);
-
- if (from == OTG_STATE_B_PERIPHERAL && otg->gadget) {
- usb_gadget_vbus_disconnect(otg->gadget);
- otg->state = OTG_STATE_A_SUSPEND;
- }
- tegra_otg_disable_clk();
+ struct tegra_otg_data *tegra = platform_get_drvdata(pdev);
+ struct otg_transceiver *otg = &tegra->otg;
+ int val;
+ DBG("%s(%d) BEGIN state : %s\n", __func__, __LINE__,
+ tegra_state_name(otg->state));
+
+ clk_enable(tegra->clk);
+ val = otg_readl(tegra, USB_PHY_WAKEUP);
+ val &= ~(USB_ID_INT_EN | USB_VBUS_INT_EN);
+ otg_writel(tegra, val, USB_PHY_WAKEUP);
+ clk_disable(tegra->clk);
+
+ /* Suspend peripheral mode, host mode is taken care by host driver */
+ if (otg->state == OTG_STATE_B_PERIPHERAL)
+ tegra_change_otg_state(tegra, OTG_STATE_A_SUSPEND);
+
+ tegra->suspended = true;
+
+ DBG("%s(%d) END\n", __func__, __LINE__);
return 0;
}
static void tegra_otg_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
- struct tegra_otg_data *tegra_otg = platform_get_drvdata(pdev);
+ struct tegra_otg_data *tegra = platform_get_drvdata(pdev);
+ struct otg_transceiver *otg = &tegra->otg;
int val;
unsigned long flags;
+ DBG("%s(%d) BEGIN\n", __func__, __LINE__);
- tegra_otg_enable_clk();
-
- /* Following delay is intentional.
- * It is placed here after observing system hang.
- * Root cause is not confirmed.
- */
- msleep(1);
- /* restore the interupt enable for cable ID and VBUS */
- clk_enable(tegra_otg->clk);
- writel(tegra_otg->intr_reg_data, (tegra_otg->regs + USB_PHY_WAKEUP));
- val = readl(tegra_otg->regs + USB_PHY_WAKEUP);
- clk_disable(tegra_otg->clk);
-
- /* A device might be connected while CPU is in sleep mode. In this case no interrupt
- * will be triggered
- * force irq_work to recheck connected devices
- */
- if (!(val & USB_ID_STATUS)) {
- spin_lock_irqsave(&tegra_otg->lock, flags);
- tegra_otg->int_status = (val | USB_ID_INT_STATUS );
- schedule_work(&tegra_otg->work);
- spin_unlock_irqrestore(&tegra_otg->lock, flags);
- }
+ if (!tegra->suspended)
+ return;
+
+ /* Clear pending interrupts */
+ clk_enable(tegra->clk);
+ val = otg_readl(tegra, USB_PHY_WAKEUP);
+ otg_writel(tegra, val, USB_PHY_WAKEUP);
+ DBG("%s(%d) PHY WAKEUP register : 0x%x\n", __func__, __LINE__, val);
+ clk_disable(tegra->clk);
+
+ /* Handle if host cable is replaced with device during suspend state */
+ if (otg->state == OTG_STATE_A_HOST && (val & USB_ID_STATUS))
+ tegra_change_otg_state(tegra, OTG_STATE_A_SUSPEND);
+
+ /* Enable interrupt and call work to set to appropriate state */
+ spin_lock_irqsave(&tegra->lock, flags);
+ if (tegra->builtin_host)
+ tegra->int_status = val | USB_INT_EN;
+ else
+ tegra->int_status = val | USB_VBUS_INT_EN | USB_VBUS_WAKEUP_EN |
+ USB_ID_PIN_WAKEUP_EN;
+
+ spin_unlock_irqrestore(&tegra->lock, flags);
+ irq_work(&tegra->work);
+
+ enable_interrupt(tegra, true);
+
+ tegra->suspended = false;
- return;
+ DBG("%s(%d) END\n", __func__, __LINE__);
}
static const struct dev_pm_ops tegra_otg_pm_ops = {
diff --git a/drivers/usb/serial/baseband_usb_chr.c b/drivers/usb/serial/baseband_usb_chr.c
index cad33d5b6f49..96db92715207 100644
--- a/drivers/usb/serial/baseband_usb_chr.c
+++ b/drivers/usb/serial/baseband_usb_chr.c
@@ -3,7 +3,7 @@
*
* USB character driver to communicate with baseband modems.
*
- * Copyright (c) 2012, NVIDIA Corporation.
+ * Copyright (c) 2012, NVIDIA Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -40,16 +40,32 @@
MODULE_LICENSE("GPL");
-unsigned long baseband_usb_chr_vid = 0x058b;
-unsigned long baseband_usb_chr_pid = 0x0041;
-unsigned long baseband_usb_chr_intf = 0x01;
+/* To add new usb devices, update
+ * (1) baseband_usb_driver_id_table
+ * - usb vendor id / product id
+ * (2) baseband_usb_driver_intf_table
+ * - usb interface number
+ */
+
+static struct usb_device_id baseband_usb_driver_id_table[] = {
+ /* XMM modem #1 BOOT ROM */
+ { USB_DEVICE(0x058b, 0x0041), },
+ /* XMM modem #2 BOOT ROM */
+ { USB_DEVICE(0x8087, 0x0716), },
+ /* empty entry required to terminate list */
+ { },
+};
+
+static unsigned int baseband_usb_driver_intf_table[] = {
+ /* XMM modem #1 BOOT ROM */
+ 0x01,
+ /* XMM modem #2 BOOT ROM */
+ 0x00,
+ /* empty entry required to terminate list */
+ 0x00,
+};
-module_param(baseband_usb_chr_vid, ulong, 0644);
-MODULE_PARM_DESC(baseband_usb_chr_vid, "baseband (usb chr) - USB VID");
-module_param(baseband_usb_chr_pid, ulong, 0644);
-MODULE_PARM_DESC(baseband_usb_chr_pid, "baseband (usb chr) - USB PID");
-module_param(baseband_usb_chr_intf, ulong, 0644);
-MODULE_PARM_DESC(baseband_usb_chr_intf, "baseband (usb chr) - USB interface");
+MODULE_DEVICE_TABLE(usb, baseband_usb_driver_id_table);
static struct baseband_usb *baseband_usb_chr;
static struct usb_interface *probe_usb_intf;
@@ -400,7 +416,7 @@ static ssize_t baseband_ipc_file_write(struct baseband_ipc *ipc,
/* do not accept write if previous tx not finished */
if (peek_ipc_tx_bufsiz(ipc, USB_CHR_TX_BUFSIZ) != 0) {
- pr_info("%s: not accepting write of %u bytes"
+ pr_debug("%s: not accepting write of %u bytes"
" - previous tx not finished\n",
__func__, count);
return 0;
@@ -649,10 +665,15 @@ static void baseband_usb_chr_rx_urb_comp(struct urb *urb)
}
switch (urb->status) {
+ case 0:
+ /* success */
+ break;
case -ENOENT:
case -ESHUTDOWN:
case -EPROTO:
pr_info("%s: link down\n", __func__);
+ default:
+ pr_err("%s: urb error status %d\n", __func__, urb->status);
return;
}
@@ -787,6 +808,8 @@ static void find_usb_pipe(struct baseband_usb *usb)
static int baseband_usb_driver_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
+ int i;
+
pr_debug("%s(%d) { intf %p id %p\n", __func__, __LINE__, intf, id);
pr_debug("intf->cur_altsetting->desc.bInterfaceNumber %02x\n",
@@ -805,10 +828,14 @@ static int baseband_usb_driver_probe(struct usb_interface *intf,
intf->cur_altsetting->desc.iInterface);
/* usb interface mismatch */
- if (baseband_usb_chr_intf !=
- intf->cur_altsetting->desc.bInterfaceNumber) {
- pr_debug("%s(%d) } -ENODEV\n", __func__, __LINE__);
- return -ENODEV;
+ for (i = 0; baseband_usb_driver_id_table[i].match_flags; i++) {
+ if (id == &baseband_usb_driver_id_table[i]) {
+ if (baseband_usb_driver_intf_table[i] !=
+ intf->cur_altsetting->desc.bInterfaceNumber) {
+ pr_debug("%s(%d) } -ENODEV\n", __func__, __LINE__);
+ return -ENODEV;
+ }
+ }
}
/* usb interface match */
@@ -844,12 +871,8 @@ static void baseband_usb_driver_disconnect(struct usb_interface *intf)
pr_debug("%s(%d) }\n", __func__, __LINE__);
}
-static char baseband_usb_driver_name[32];
-
-static struct usb_device_id baseband_usb_driver_id_table[2];
-
static struct usb_driver baseband_usb_driver = {
- .name = baseband_usb_driver_name,
+ .name = "bb_usb_chr",
.probe = baseband_usb_driver_probe,
.disconnect = baseband_usb_driver_disconnect,
.id_table = baseband_usb_driver_id_table,
@@ -924,6 +947,9 @@ static void baseband_usb_close(struct baseband_usb *usb)
if (!usb)
return;
+ /* we need proper lock, maybe...*/
+ usb_device_connection = false;
+
/* free re-usable rx urb + rx urb transfer buffer */
if (usb->usb.rx_urb) {
pr_debug("%s: free rx urb\n", __func__);
@@ -936,7 +962,6 @@ static void baseband_usb_close(struct baseband_usb *usb)
}
if (usb->ipc) {
- usb_device_connection = false;
flush_work_sync(&usb->ipc->work);
flush_work_sync(&usb->ipc->rx_work);
}
@@ -963,10 +988,7 @@ static void baseband_usb_close(struct baseband_usb *usb)
pr_debug("baseband_usb_close }\n");
}
-static struct baseband_usb *baseband_usb_open(unsigned int vid,
- unsigned int pid,
- unsigned int intf,
- work_func_t work_func,
+static struct baseband_usb *baseband_usb_open(work_func_t work_func,
work_func_t rx_work_func,
work_func_t tx_work_func)
{
@@ -994,13 +1016,6 @@ static struct baseband_usb *baseband_usb_open(unsigned int vid,
/* open usb driver */
probe_usb_intf = (struct usb_interface *) 0;
- sprintf(baseband_usb_driver_name,
- "baseband_usb_%x_%x_%x",
- vid, pid, intf);
- baseband_usb_driver_id_table[0].match_flags
- = USB_DEVICE_ID_MATCH_DEVICE;
- baseband_usb_driver_id_table[0].idVendor = vid;
- baseband_usb_driver_id_table[0].idProduct = pid;
usb->usb.driver = &baseband_usb_driver;
err = usb_register(&baseband_usb_driver);
if (err < 0) {
@@ -1091,10 +1106,7 @@ static int baseband_usb_chr_open(struct inode *inode, struct file *file)
}
/* open baseband usb */
- baseband_usb_chr = baseband_usb_open(baseband_usb_chr_vid,
- baseband_usb_chr_pid,
- baseband_usb_chr_intf,
- baseband_usb_chr_work,
+ baseband_usb_chr = baseband_usb_open(baseband_usb_chr_work,
baseband_usb_chr_rx_urb_comp_work,
(work_func_t) 0);
if (!baseband_usb_chr) {
diff --git a/drivers/video/backlight/tegra_pwm_bl.c b/drivers/video/backlight/tegra_pwm_bl.c
index 4be691c54d3a..a9a429e5c837 100644
--- a/drivers/video/backlight/tegra_pwm_bl.c
+++ b/drivers/video/backlight/tegra_pwm_bl.c
@@ -20,6 +20,7 @@
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/tegra_pwm_bl.h>
+#include <linux/gpio.h>
#include <mach/dc.h>
struct tegra_pwm_bl_data {
@@ -112,11 +113,17 @@ static int tegra_pwm_backlight_probe(struct platform_device *pdev)
tbl->check_fb = data->check_fb;
tbl->params.which_pwm = data->which_pwm;
tbl->params.gpio_conf_to_sfio = data->gpio_conf_to_sfio;
- tbl->params.switch_to_sfio = data->switch_to_sfio;
tbl->params.period = data->period;
tbl->params.clk_div = data->clk_div;
tbl->params.clk_select = data->clk_select;
+ /* If backlight pin is sfio, request for it */
+ if (gpio_is_valid(tbl->params.gpio_conf_to_sfio)) {
+ ret = gpio_request(tbl->params.gpio_conf_to_sfio, "disp_bl");
+ if (ret)
+ dev_err(&pdev->dev, "backlight gpio request failed\n");
+ }
+
memset(&props, 0, sizeof(struct backlight_properties));
props.type = BACKLIGHT_RAW;
props.max_brightness = data->max_brightness;
@@ -129,6 +136,9 @@ static int tegra_pwm_backlight_probe(struct platform_device *pdev)
}
bl->props.brightness = data->dft_brightness;
+
+ if (gpio_is_valid(tbl->params.gpio_conf_to_sfio))
+ gpio_free(tbl->params.gpio_conf_to_sfio);
backlight_update_status(bl);
platform_set_drvdata(pdev, bl);
diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c
index 473875a3ae78..5e15a92609b0 100644
--- a/drivers/video/mx3fb.c
+++ b/drivers/video/mx3fb.c
@@ -1103,13 +1103,8 @@ static int mx3fb_pan_display(struct fb_var_screeninfo *var,
if (mx3_fbi->txd)
async_tx_ack(mx3_fbi->txd);
-<<<<<<< HEAD
- txd = dma_chan->device->device_prep_slave_sg(dma_chan, sg +
- mx3_fbi->cur_ipu_buf, 1, DMA_TO_DEVICE, DMA_PREP_INTERRUPT);
-=======
txd = dmaengine_prep_slave_sg(dma_chan, sg +
mx3_fbi->cur_ipu_buf, 1, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
->>>>>>> 1605282... dmaengine/dma_slave: introduce inline wrappers
if (!txd) {
dev_err(fbi->device,
"Error preparing a DMA transaction descriptor.\n");
diff --git a/drivers/video/tegra/Kconfig b/drivers/video/tegra/Kconfig
index 468a5566b667..b5540a5793b2 100644
--- a/drivers/video/tegra/Kconfig
+++ b/drivers/video/tegra/Kconfig
@@ -7,6 +7,21 @@ config TEGRA_GRHOST
help
Driver for the Tegra graphics host hardware.
+config TEGRA_GRHOST_USE_NVMAP
+ bool "Use nvmap as graphics memory manager"
+ default y
+ help
+ Use nvmap as the graphics memory manager. This is the only
+ choice at the moment.
+
+config TEGRA_GRHOST_DEFAULT_TIMEOUT
+ depends on TEGRA_GRHOST
+ int "Default timeout for submits"
+ default 0 if TEGRA_SIMULATION_PLATFORM
+ default 30000
+ help
+ Default timeout for jobs in milliseconds. Set to zero for no timeout.
+
config TEGRA_DC
tristate "Tegra Display Contoller"
depends on ARCH_TEGRA && TEGRA_GRHOST
@@ -35,6 +50,7 @@ config TEGRA_DC_EXTENSIONS
config TEGRA_NVMAP
bool "Tegra GPU memory management driver (nvmap)"
+ select ARM_DMA_USE_IOMMU if IOMMU_API
default y
help
Say Y here to include the memory management driver for the Tegra
@@ -42,7 +58,7 @@ config TEGRA_NVMAP
config NVMAP_RECLAIM_UNPINNED_VM
bool "Virtualize IOVMM memory in nvmap"
- depends on TEGRA_NVMAP && TEGRA_IOVMM
+ depends on TEGRA_NVMAP && (TEGRA_IOVMM || IOMMU_API)
default y
help
Say Y here to enable nvmap to reclaim I/O virtual memory after
@@ -61,7 +77,7 @@ config NVMAP_ALLOW_SYSMEM
config NVMAP_HIGHMEM_ONLY
bool "Use only HIGHMEM for nvmap"
- depends on TEGRA_NVMAP && (NVMAP_ALLOW_SYSMEM || TEGRA_IOVMM) && HIGHMEM
+ depends on TEGRA_NVMAP && (NVMAP_ALLOW_SYSMEM || TEGRA_IOVMM || IOMMU_API) && HIGHMEM
default n
help
Say Y here to restrict nvmap system memory allocations (both
@@ -85,6 +101,31 @@ config NVMAP_CARVEOUT_COMPACTOR
heap and retries the failed allocation.
Say Y here to let nvmap to keep carveout fragmentation under control.
+config NVMAP_PAGE_POOLS
+ bool "Use page pools to reduce allocation overhead"
+ depends on TEGRA_NVMAP
+ default y
+ help
+ say Y here to reduce the alloction overhead, which is significant
+ for uncached, writecombine and inner cacheable memories as it
+ involves changing page attributes during every allocation per page
+ and flushing cache. Alloc time is reduced by allcoating the pages
+ ahead and keeping them aside. The reserved pages would be released
+ when system is low on memory and acquired back during release of
+ memory.
+
+config NVMAP_PAGE_POOL_SIZE
+ hex
+ default 0x0
+
+config NVMAP_CACHE_MAINT_BY_SET_WAYS
+ bool "Enalbe cache maintenance by set/ways"
+ depends on TEGRA_NVMAP
+ help
+ Say Y here to reduce cache maintenance overhead by MVA.
+ This helps in reducing cache maintenance overhead in the systems,
+ where inner cache includes only L1. For the systems, where inner cache
+ includes L1 and L2, keep this option disabled.
config NVMAP_VPR
bool "Enable VPR Heap."
@@ -102,7 +143,7 @@ config TEGRA_DSI
config NVMAP_CONVERT_CARVEOUT_TO_IOVMM
bool "Convert carveout to IOVMM"
- depends on TEGRA_NVMAP && TEGRA_IOVMM_SMMU
+ depends on TEGRA_NVMAP && (TEGRA_IOVMM_SMMU || IOMMU_API)
default y
help
Say Y here to force to convert carveout memory requests to
diff --git a/drivers/video/tegra/Makefile b/drivers/video/tegra/Makefile
index 2299a3c5eaa3..ce581d2c81a3 100644
--- a/drivers/video/tegra/Makefile
+++ b/drivers/video/tegra/Makefile
@@ -1,4 +1,6 @@
GCOV_PROFILE := y
+subdir-ccflags-y := -Werror
+EXTRA_CFLAGS += -Idrivers/video/tegra/host
obj-$(CONFIG_TEGRA_GRHOST) += host/
obj-$(CONFIG_TEGRA_DC) += dc/
obj-$(CONFIG_FB_TEGRA) += fb.o
diff --git a/drivers/video/tegra/dc/Makefile b/drivers/video/tegra/dc/Makefile
index 01f13918ca63..59104c681bae 100644
--- a/drivers/video/tegra/dc/Makefile
+++ b/drivers/video/tegra/dc/Makefile
@@ -1,5 +1,6 @@
GCOV_PROFILE := y
-obj-y += dc.o
+EXTRA_CFLAGS += -Idrivers/video/tegra/host
+obj-y += dc.o bandwidth.o mode.o clock.o lut.o csc.o window.o
obj-y += rgb.o
obj-y += hdmi.o
obj-$(CONFIG_TEGRA_NVHDCP) += nvhdcp.o
@@ -7,4 +8,5 @@ obj-y += edid.o
obj-y += nvsd.o
obj-y += dsi.o
obj-y += dc_sysfs.o
+obj-y += dc_config.o
obj-$(CONFIG_TEGRA_DC_EXTENSIONS) += ext/
diff --git a/drivers/video/tegra/dc/bandwidth.c b/drivers/video/tegra/dc/bandwidth.c
new file mode 100644
index 000000000000..0b307f4bc4a2
--- /dev/null
+++ b/drivers/video/tegra/dc/bandwidth.c
@@ -0,0 +1,284 @@
+/*
+ * drivers/video/tegra/dc/bandwidth.c
+ *
+ * Copyright (c) 2010-2012, NVIDIA CORPORATION, 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/module.h>
+#include <linux/kernel.h>
+#include <linux/clk.h>
+
+#include <mach/clk.h>
+#include <mach/dc.h>
+#include <mach/fb.h>
+#include <mach/mc.h>
+#include <linux/nvhost.h>
+#include <mach/latency_allowance.h>
+
+#include "dc_reg.h"
+#include "dc_config.h"
+#include "dc_priv.h"
+
+static int use_dynamic_emc = 1;
+
+module_param_named(use_dynamic_emc, use_dynamic_emc, int, S_IRUGO | S_IWUSR);
+
+/* uses the larger of w->bandwidth or w->new_bandwidth */
+static void tegra_dc_set_latency_allowance(struct tegra_dc *dc,
+ struct tegra_dc_win *w)
+{
+ /* windows A, B, C for first and second display */
+ static const enum tegra_la_id la_id_tab[2][3] = {
+ /* first display */
+ { TEGRA_LA_DISPLAY_0A, TEGRA_LA_DISPLAY_0B,
+ TEGRA_LA_DISPLAY_0C },
+ /* second display */
+ { TEGRA_LA_DISPLAY_0AB, TEGRA_LA_DISPLAY_0BB,
+ TEGRA_LA_DISPLAY_0CB },
+ };
+ /* window B V-filter tap for first and second display. */
+ static const enum tegra_la_id vfilter_tab[2] = {
+ TEGRA_LA_DISPLAY_1B, TEGRA_LA_DISPLAY_1BB,
+ };
+ unsigned long bw;
+
+ BUG_ON(dc->ndev->id >= ARRAY_SIZE(la_id_tab));
+ BUG_ON(dc->ndev->id >= ARRAY_SIZE(vfilter_tab));
+ BUG_ON(w->idx >= ARRAY_SIZE(*la_id_tab));
+
+ bw = max(w->bandwidth, w->new_bandwidth);
+
+ /* tegra_dc_get_bandwidth() treats V filter windows as double
+ * bandwidth, but LA has a seperate client for V filter */
+ if (w->idx == 1 && win_use_v_filter(dc, w))
+ bw /= 2;
+
+ /* our bandwidth is in kbytes/sec, but LA takes MBps.
+ * round up bandwidth to next 1MBps */
+ bw = bw / 1000 + 1;
+
+#ifdef CONFIG_TEGRA_SILICON_PLATFORM
+ tegra_set_latency_allowance(la_id_tab[dc->ndev->id][w->idx], bw);
+ /* if window B, also set the 1B client for the 2-tap V filter. */
+ if (w->idx == 1)
+ tegra_set_latency_allowance(vfilter_tab[dc->ndev->id], bw);
+#endif
+}
+
+static unsigned int tegra_dc_windows_is_overlapped(struct tegra_dc_win *a,
+ struct tegra_dc_win *b)
+{
+ if (!WIN_IS_ENABLED(a) || !WIN_IS_ENABLED(b))
+ return 0;
+
+ /* because memory access to load the fifo can overlap, only care
+ * if windows overlap vertically */
+ return ((a->out_y + a->out_h > b->out_y) && (a->out_y <= b->out_y)) ||
+ ((b->out_y + b->out_h > a->out_y) && (b->out_y <= a->out_y));
+}
+
+static unsigned long tegra_dc_find_max_bandwidth(struct tegra_dc_win *wins[],
+ int n)
+{
+ unsigned i;
+ unsigned j;
+ unsigned overlap_count;
+ unsigned max_bw = 0;
+
+ WARN_ONCE(n > 3, "Code assumes at most 3 windows, bandwidth is likely"
+ "inaccurate.\n");
+
+ /* If we had a large number of windows, we would compute adjacency
+ * graph representing 2 window overlaps, find all cliques in the graph,
+ * assign bandwidth to each clique, and then select the clique with
+ * maximum bandwidth. But because we have at most 3 windows,
+ * implementing proper Bron-Kerbosh algorithm would be an overkill,
+ * brute force will suffice.
+ *
+ * Thus: find maximum bandwidth for either single or a pair of windows
+ * and count number of window pair overlaps. If there are three
+ * pairs, all 3 window overlap.
+ */
+
+ overlap_count = 0;
+ for (i = 0; i < n; i++) {
+ unsigned int bw1;
+
+ if (wins[i] == NULL)
+ continue;
+ bw1 = wins[i]->new_bandwidth;
+ if (bw1 > max_bw)
+ /* Single window */
+ max_bw = bw1;
+
+ for (j = i + 1; j < n; j++) {
+ if (wins[j] == NULL)
+ continue;
+ if (tegra_dc_windows_is_overlapped(wins[i], wins[j])) {
+ unsigned int bw2 = wins[j]->new_bandwidth;
+ if (bw1 + bw2 > max_bw)
+ /* Window pair overlaps */
+ max_bw = bw1 + bw2;
+ overlap_count++;
+ }
+ }
+ }
+
+ if (overlap_count == 3)
+ /* All three windows overlap */
+ max_bw = wins[0]->new_bandwidth + wins[1]->new_bandwidth +
+ wins[2]->new_bandwidth;
+
+ return max_bw;
+}
+
+/*
+ * Calculate peak EMC bandwidth for each enabled window =
+ * pixel_clock * win_bpp * (use_v_filter ? 2 : 1)) * H_scale_factor *
+ * (windows_tiling ? 2 : 1)
+ *
+ * note:
+ * (*) We use 2 tap V filter, so need double BW if use V filter
+ * (*) Tiling mode on T30 and DDR3 requires double BW
+ *
+ * return:
+ * bandwidth in kBps
+ */
+static unsigned long tegra_dc_calc_win_bandwidth(struct tegra_dc *dc,
+ struct tegra_dc_win *w)
+{
+ unsigned long ret;
+ int tiled_windows_bw_multiplier;
+ unsigned long bpp;
+
+ if (!WIN_IS_ENABLED(w))
+ return 0;
+
+ if (dfixed_trunc(w->w) == 0 || dfixed_trunc(w->h) == 0 ||
+ w->out_w == 0 || w->out_h == 0)
+ return 0;
+
+ tiled_windows_bw_multiplier =
+ tegra_mc_get_tiled_memory_bandwidth_multiplier();
+
+ /* all of tegra's YUV formats(420 and 422) fetch 2 bytes per pixel,
+ * but the size reported by tegra_dc_fmt_bpp for the planar version
+ * is of the luma plane's size only. */
+ bpp = tegra_dc_is_yuv_planar(w->fmt) ?
+ 2 * tegra_dc_fmt_bpp(w->fmt) : tegra_dc_fmt_bpp(w->fmt);
+ ret = dc->mode.pclk / 1000UL * bpp / 8 * (
+ win_use_v_filter(dc, w) ? 2 : 1) *
+ dfixed_trunc(w->w) / w->out_w * (WIN_IS_TILED(w) ?
+ tiled_windows_bw_multiplier : 1);
+
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ /*
+ * Assuming 60% efficiency: i.e. if we calculate we need 70MBps, we
+ * will request 117MBps from EMC.
+ */
+ ret = ret + (17 * ret / 25);
+#endif
+ return ret;
+}
+
+static unsigned long tegra_dc_get_bandwidth(
+ struct tegra_dc_win *windows[], int n)
+{
+ int i;
+
+ BUG_ON(n > DC_N_WINDOWS);
+
+ /* emc rate and latency allowance both need to know per window
+ * bandwidths */
+ for (i = 0; i < n; i++) {
+ struct tegra_dc_win *w = windows[i];
+
+ if (w)
+ w->new_bandwidth =
+ tegra_dc_calc_win_bandwidth(w->dc, w);
+ }
+
+ return tegra_dc_find_max_bandwidth(windows, n);
+}
+
+/* to save power, call when display memory clients would be idle */
+void tegra_dc_clear_bandwidth(struct tegra_dc *dc)
+{
+ trace_printk("%s:%s rate=%d\n", dc->ndev->name, __func__,
+ dc->emc_clk_rate);
+ if (tegra_is_clk_enabled(dc->emc_clk))
+ clk_disable(dc->emc_clk);
+ dc->emc_clk_rate = 0;
+}
+
+/* use the larger of dc->emc_clk_rate or dc->new_emc_clk_rate, and copies
+ * dc->new_emc_clk_rate into dc->emc_clk_rate.
+ * calling this function both before and after a flip is sufficient to select
+ * the best possible frequency and latency allowance.
+ * set use_new to true to force dc->new_emc_clk_rate programming.
+ */
+void tegra_dc_program_bandwidth(struct tegra_dc *dc, bool use_new)
+{
+ unsigned i;
+
+ if (use_new || dc->emc_clk_rate != dc->new_emc_clk_rate) {
+ /* going from 0 to non-zero */
+ if (!dc->emc_clk_rate && !tegra_is_clk_enabled(dc->emc_clk))
+ clk_enable(dc->emc_clk);
+
+ clk_set_rate(dc->emc_clk,
+ max(dc->emc_clk_rate, dc->new_emc_clk_rate));
+ dc->emc_clk_rate = dc->new_emc_clk_rate;
+
+ /* going from non-zero to 0 */
+ if (!dc->new_emc_clk_rate && tegra_is_clk_enabled(dc->emc_clk))
+ clk_disable(dc->emc_clk);
+ }
+
+ for (i = 0; i < DC_N_WINDOWS; i++) {
+ struct tegra_dc_win *w = &dc->windows[i];
+
+ if ((use_new || w->bandwidth != w->new_bandwidth) &&
+ w->new_bandwidth != 0)
+ tegra_dc_set_latency_allowance(dc, w);
+ w->bandwidth = w->new_bandwidth;
+ trace_printk("%s:win%u bandwidth=%d\n", dc->ndev->name, w->idx,
+ w->bandwidth);
+ }
+}
+
+int tegra_dc_set_dynamic_emc(struct tegra_dc_win *windows[], int n)
+{
+ unsigned long new_rate;
+ struct tegra_dc *dc;
+
+ if (!use_dynamic_emc)
+ return 0;
+
+ dc = windows[0]->dc;
+
+ /* calculate the new rate based on this POST */
+ new_rate = tegra_dc_get_bandwidth(windows, n);
+ if (WARN_ONCE(new_rate > (ULONG_MAX / 1000), "bandwidth maxed out\n"))
+ new_rate = ULONG_MAX;
+ else
+ new_rate = EMC_BW_TO_FREQ(new_rate * 1000);
+
+ if (tegra_dc_has_multiple_dc())
+ new_rate = ULONG_MAX;
+
+ trace_printk("%s:new_emc_clk_rate=%ld\n", dc->ndev->name, new_rate);
+ dc->new_emc_clk_rate = new_rate;
+
+ return 0;
+}
diff --git a/drivers/video/tegra/dc/clock.c b/drivers/video/tegra/dc/clock.c
new file mode 100644
index 000000000000..c785282693e6
--- /dev/null
+++ b/drivers/video/tegra/dc/clock.c
@@ -0,0 +1,150 @@
+/*
+ * drivers/video/tegra/dc/clock.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * Copyright (c) 2010-2012, NVIDIA CORPORATION, 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/err.h>
+#include <linux/types.h>
+#include <linux/clk.h>
+
+#include <mach/clk.h>
+#include <mach/dc.h>
+
+#include "dc_reg.h"
+#include "dc_priv.h"
+
+unsigned long tegra_dc_pclk_round_rate(struct tegra_dc *dc, int pclk)
+{
+ unsigned long rate;
+ unsigned long div;
+
+ rate = tegra_dc_clk_get_rate(dc);
+
+ div = DIV_ROUND_CLOSEST(rate * 2, pclk);
+
+ if (div < 2)
+ return 0;
+
+ return rate * 2 / div;
+}
+
+static unsigned long tegra_dc_pclk_predict_rate(struct clk *parent, int pclk)
+{
+ unsigned long rate;
+ unsigned long div;
+
+ rate = clk_get_rate(parent);
+
+ div = DIV_ROUND_CLOSEST(rate * 2, pclk);
+
+ if (div < 2)
+ return 0;
+
+ return rate * 2 / div;
+}
+
+void tegra_dc_setup_clk(struct tegra_dc *dc, struct clk *clk)
+{
+ int pclk;
+
+ if (dc->out->type == TEGRA_DC_OUT_RGB) {
+ unsigned long rate;
+ struct clk *parent_clk =
+ clk_get_sys(NULL, dc->out->parent_clk ? : "pll_p");
+
+ if (dc->out->parent_clk_backup &&
+ (parent_clk == clk_get_sys(NULL, "pll_p"))) {
+ rate = tegra_dc_pclk_predict_rate(
+ parent_clk, dc->mode.pclk);
+ /* use pll_d as last resort */
+ if (rate < (dc->mode.pclk / 100 * 99) ||
+ rate > (dc->mode.pclk / 100 * 109))
+ parent_clk = clk_get_sys(
+ NULL, dc->out->parent_clk_backup);
+ }
+
+ if (clk_get_parent(clk) != parent_clk)
+ clk_set_parent(clk, parent_clk);
+
+ if (parent_clk != clk_get_sys(NULL, "pll_p")) {
+ struct clk *base_clk = clk_get_parent(parent_clk);
+
+ /* Assuming either pll_d or pll_d2 is used */
+ rate = dc->mode.pclk * 2;
+
+ if (rate != clk_get_rate(base_clk))
+ clk_set_rate(base_clk, rate);
+ }
+ }
+
+ if (dc->out->type == TEGRA_DC_OUT_HDMI) {
+ unsigned long rate;
+ struct clk *parent_clk = clk_get_sys(NULL,
+ dc->out->parent_clk ? : "pll_d_out0");
+ struct clk *base_clk = clk_get_parent(parent_clk);
+
+ /*
+ * Providing dynamic frequency rate setting for T20/T30 HDMI.
+ * The required rate needs to be setup at 4x multiplier,
+ * as out0 is 1/2 of the actual PLL output.
+ */
+
+ rate = dc->mode.pclk * 4;
+ if (rate != clk_get_rate(base_clk))
+ clk_set_rate(base_clk, rate);
+
+ if (clk_get_parent(clk) != parent_clk)
+ clk_set_parent(clk, parent_clk);
+ }
+
+ if (dc->out->type == TEGRA_DC_OUT_DSI) {
+ unsigned long rate;
+ struct clk *parent_clk;
+ struct clk *base_clk;
+
+ if (clk == dc->clk) {
+ parent_clk = clk_get_sys(NULL,
+ dc->out->parent_clk ? : "pll_d_out0");
+ base_clk = clk_get_parent(parent_clk);
+ tegra_clk_cfg_ex(base_clk,
+ TEGRA_CLK_PLLD_DSI_OUT_ENB, 1);
+ } else {
+ if (dc->pdata->default_out->dsi->dsi_instance) {
+ parent_clk = clk_get_sys(NULL,
+ dc->out->parent_clk ? : "pll_d2_out0");
+ base_clk = clk_get_parent(parent_clk);
+ tegra_clk_cfg_ex(base_clk,
+ TEGRA_CLK_PLLD_CSI_OUT_ENB, 1);
+ } else {
+ parent_clk = clk_get_sys(NULL,
+ dc->out->parent_clk ? : "pll_d_out0");
+ base_clk = clk_get_parent(parent_clk);
+ tegra_clk_cfg_ex(base_clk,
+ TEGRA_CLK_PLLD_DSI_OUT_ENB, 1);
+ }
+ }
+
+ rate = dc->mode.pclk * dc->shift_clk_div * 2;
+ if (rate != clk_get_rate(base_clk))
+ clk_set_rate(base_clk, rate);
+
+ if (clk_get_parent(clk) != parent_clk)
+ clk_set_parent(clk, parent_clk);
+ }
+
+ pclk = tegra_dc_pclk_round_rate(dc, dc->mode.pclk);
+ tegra_dvfs_set_rate(clk, pclk);
+}
diff --git a/drivers/video/tegra/dc/csc.c b/drivers/video/tegra/dc/csc.c
new file mode 100644
index 000000000000..74fa900352a1
--- /dev/null
+++ b/drivers/video/tegra/dc/csc.c
@@ -0,0 +1,67 @@
+/*
+ * drivers/video/tegra/dc/csc.c
+ *
+ * Copyright (c) 2010-2012, NVIDIA CORPORATION, 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/err.h>
+#include <linux/types.h>
+#include <mach/dc.h>
+
+#include "dc_reg.h"
+#include "dc_priv.h"
+
+void tegra_dc_init_csc_defaults(struct tegra_dc_csc *csc)
+{
+ csc->yof = 0x00f0;
+ csc->kyrgb = 0x012a;
+ csc->kur = 0x0000;
+ csc->kvr = 0x0198;
+ csc->kug = 0x039b;
+ csc->kvg = 0x032f;
+ csc->kub = 0x0204;
+ csc->kvb = 0x0000;
+}
+
+void tegra_dc_set_csc(struct tegra_dc *dc, struct tegra_dc_csc *csc)
+{
+ tegra_dc_writel(dc, csc->yof, DC_WIN_CSC_YOF);
+ tegra_dc_writel(dc, csc->kyrgb, DC_WIN_CSC_KYRGB);
+ tegra_dc_writel(dc, csc->kur, DC_WIN_CSC_KUR);
+ tegra_dc_writel(dc, csc->kvr, DC_WIN_CSC_KVR);
+ tegra_dc_writel(dc, csc->kug, DC_WIN_CSC_KUG);
+ tegra_dc_writel(dc, csc->kvg, DC_WIN_CSC_KVG);
+ tegra_dc_writel(dc, csc->kub, DC_WIN_CSC_KUB);
+ tegra_dc_writel(dc, csc->kvb, DC_WIN_CSC_KVB);
+}
+
+int tegra_dc_update_csc(struct tegra_dc *dc, int win_idx)
+{
+ mutex_lock(&dc->lock);
+
+ if (!dc->enabled) {
+ mutex_unlock(&dc->lock);
+ return -EFAULT;
+ }
+
+ tegra_dc_writel(dc, WINDOW_A_SELECT << win_idx,
+ DC_CMD_DISPLAY_WINDOW_HEADER);
+
+ tegra_dc_set_csc(dc, &dc->windows[win_idx].csc);
+
+ mutex_unlock(&dc->lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(tegra_dc_update_csc);
+
diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c
index c42df4c1957e..1f7e2ce67682 100644
--- a/drivers/video/tegra/dc/dc.c
+++ b/drivers/video/tegra/dc/dc.c
@@ -4,7 +4,7 @@
* Copyright (C) 2010 Google, Inc.
* Author: Erik Gilling <konkers@android.com>
*
- * Copyright (C) 2010-2012 NVIDIA Corporation
+ * Copyright (c) 2010-2012, NVIDIA CORPORATION, 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
@@ -34,13 +34,13 @@
#include <linux/seq_file.h>
#include <linux/backlight.h>
#include <linux/gpio.h>
+#include <linux/nvhost.h>
#include <video/tegrafb.h>
#include <drm/drm_fixed.h>
#ifdef CONFIG_SWITCH
#include <linux/switch.h>
#endif
-
#include <mach/clk.h>
#include <mach/dc.h>
#include <mach/fb.h>
@@ -49,6 +49,7 @@
#include <mach/latency_allowance.h>
#include "dc_reg.h"
+#include "dc_config.h"
#include "dc_priv.h"
#include "nvsd.h"
@@ -57,14 +58,6 @@
#define DC_COM_PIN_OUTPUT_POLARITY1_INIT_VAL 0x01000000
#define DC_COM_PIN_OUTPUT_POLARITY3_INIT_VAL 0x0
-#ifndef CONFIG_TEGRA_FPGA_PLATFORM
-#define ALL_UF_INT (WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT)
-#else
-/* ignore underflows when on simulation and fpga platform */
-#define ALL_UF_INT (0)
-#endif
-
-static int no_vsync;
static struct fb_videomode tegra_dc_hdmi_fallback_mode = {
.refresh = 60,
.xres = 640,
@@ -80,119 +73,29 @@ static struct fb_videomode tegra_dc_hdmi_fallback_mode = {
.sync = 0,
};
-static void _tegra_dc_controller_disable(struct tegra_dc *dc);
-
-module_param_named(no_vsync, no_vsync, int, S_IRUGO | S_IWUSR);
-
-static int use_dynamic_emc = 1;
+static struct tegra_dc_mode override_disp_mode[3];
-module_param_named(use_dynamic_emc, use_dynamic_emc, int, S_IRUGO | S_IWUSR);
+static void _tegra_dc_controller_disable(struct tegra_dc *dc);
struct tegra_dc *tegra_dcs[TEGRA_MAX_DC];
DEFINE_MUTEX(tegra_dc_lock);
DEFINE_MUTEX(shared_lock);
-static const struct {
- bool h;
- bool v;
-} can_filter[] = {
- /* Window A has no filtering */
- { false, false },
- /* Window B has both H and V filtering */
- { true, true },
- /* Window C has only H filtering */
- { false, true },
-};
-static inline bool win_use_v_filter(const struct tegra_dc_win *win)
+static inline void tegra_dc_clk_enable(struct tegra_dc *dc)
{
- return can_filter[win->idx].v &&
- win->h.full != dfixed_const(win->out_h);
-}
-static inline bool win_use_h_filter(const struct tegra_dc_win *win)
-{
- return can_filter[win->idx].h &&
- win->w.full != dfixed_const(win->out_w);
-}
-
-static inline int tegra_dc_fmt_bpp(int fmt)
-{
- switch (fmt) {
- case TEGRA_WIN_FMT_P1:
- return 1;
-
- case TEGRA_WIN_FMT_P2:
- return 2;
-
- case TEGRA_WIN_FMT_P4:
- return 4;
-
- case TEGRA_WIN_FMT_P8:
- return 8;
-
- case TEGRA_WIN_FMT_B4G4R4A4:
- case TEGRA_WIN_FMT_B5G5R5A:
- case TEGRA_WIN_FMT_B5G6R5:
- case TEGRA_WIN_FMT_AB5G5R5:
- return 16;
-
- case TEGRA_WIN_FMT_B8G8R8A8:
- case TEGRA_WIN_FMT_R8G8B8A8:
- case TEGRA_WIN_FMT_B6x2G6x2R6x2A8:
- case TEGRA_WIN_FMT_R6x2G6x2B6x2A8:
- return 32;
-
- /* for planar formats, size of the Y plane, 8bit */
- case TEGRA_WIN_FMT_YCbCr420P:
- case TEGRA_WIN_FMT_YUV420P:
- case TEGRA_WIN_FMT_YCbCr422P:
- case TEGRA_WIN_FMT_YUV422P:
- case TEGRA_WIN_FMT_YCbCr422R:
- case TEGRA_WIN_FMT_YUV422R:
- case TEGRA_WIN_FMT_YCbCr422RA:
- case TEGRA_WIN_FMT_YUV422RA:
- return 8;
-
- /* YUYV packed into 32-bits */
- case TEGRA_WIN_FMT_YCbCr422:
- case TEGRA_WIN_FMT_YUV422:
- return 16;
- }
- return 0;
-}
-
-static inline bool tegra_dc_is_yuv(int fmt)
-{
- switch (fmt) {
- case TEGRA_WIN_FMT_YUV420P:
- case TEGRA_WIN_FMT_YCbCr420P:
- case TEGRA_WIN_FMT_YCbCr422P:
- case TEGRA_WIN_FMT_YUV422P:
- case TEGRA_WIN_FMT_YCbCr422:
- case TEGRA_WIN_FMT_YUV422:
- case TEGRA_WIN_FMT_YCbCr422R:
- case TEGRA_WIN_FMT_YUV422R:
- case TEGRA_WIN_FMT_YCbCr422RA:
- case TEGRA_WIN_FMT_YUV422RA:
- return true;
+ if (!tegra_is_clk_enabled(dc->clk)) {
+ clk_enable(dc->clk);
+ tegra_dvfs_set_rate(dc->clk, dc->mode.pclk);
}
- return false;
}
-static inline bool tegra_dc_is_yuv_planar(int fmt)
+static inline void tegra_dc_clk_disable(struct tegra_dc *dc)
{
- switch (fmt) {
- case TEGRA_WIN_FMT_YUV420P:
- case TEGRA_WIN_FMT_YCbCr420P:
- case TEGRA_WIN_FMT_YCbCr422P:
- case TEGRA_WIN_FMT_YUV422P:
- case TEGRA_WIN_FMT_YCbCr422R:
- case TEGRA_WIN_FMT_YUV422R:
- case TEGRA_WIN_FMT_YCbCr422RA:
- case TEGRA_WIN_FMT_YUV422RA:
- return true;
+ if (tegra_is_clk_enabled(dc->clk)) {
+ clk_disable(dc->clk);
+ tegra_dvfs_set_rate(dc->clk, 0);
}
- return false;
}
#define DUMP_REG(a) do { \
@@ -201,23 +104,6 @@ static inline bool tegra_dc_is_yuv_planar(int fmt)
print(data, buff); \
} while (0)
-#define print_mode_info(dc, mode) do { \
- trace_printk("%s:Mode settings: " \
- "ref_to_sync: H = %d V = %d, " \
- "sync_width: H = %d V = %d, " \
- "back_porch: H = %d V = %d, " \
- "active: H = %d V = %d, " \
- "front_porch: H = %d V = %d, " \
- "pclk = %d, stereo mode = %d\n", \
- dc->ndev->name, \
- mode.h_ref_to_sync, mode.v_ref_to_sync, \
- mode.h_sync_width, mode.v_sync_width, \
- mode.h_back_porch, mode.v_back_porch, \
- mode.h_active, mode.v_active, \
- mode.h_front_porch, mode.v_front_porch, \
- mode.pclk, mode.stereo_mode); \
- } while (0)
-
#define print_underflow_info(dc) do { \
trace_printk("%s:Underflow stats: underflows : %llu, " \
"undeflows_a : %llu, " \
@@ -236,7 +122,7 @@ static void _dump_regs(struct tegra_dc *dc, void *data,
char buff[256];
tegra_dc_io_start(dc);
- clk_enable(dc->clk);
+ tegra_dc_clk_enable(dc);
DUMP_REG(DC_CMD_DISPLAY_COMMAND_OPTION0);
DUMP_REG(DC_CMD_DISPLAY_COMMAND);
@@ -386,7 +272,7 @@ static void _dump_regs(struct tegra_dc *dc, void *data,
DUMP_REG(DC_COM_PM1_DUTY_CYCLE);
DUMP_REG(DC_DISP_SD_CONTROL);
- clk_disable(dc->clk);
+ tegra_dc_clk_disable(dc);
tegra_dc_io_end(dc);
}
@@ -579,7 +465,7 @@ out:
return ret;
}
-static unsigned int tegra_dc_has_multiple_dc(void)
+unsigned int tegra_dc_has_multiple_dc(void)
{
unsigned int idx;
unsigned int cnt = 0;
@@ -593,6 +479,22 @@ static unsigned int tegra_dc_has_multiple_dc(void)
return (cnt > 1);
}
+/* get the stride size of a window.
+ * return: stride size in bytes for window win. or 0 if unavailble. */
+int tegra_dc_get_stride(struct tegra_dc *dc, unsigned win)
+{
+ u32 stride;
+
+ if (!dc->enabled)
+ return 0;
+ BUG_ON(win > DC_N_WINDOWS);
+ tegra_dc_writel(dc, WINDOW_A_SELECT << win,
+ DC_CMD_DISPLAY_WINDOW_HEADER);
+ stride = tegra_dc_readl(dc, DC_WIN_LINE_STRIDE);
+ return GET_LINE_STRIDE(stride);
+}
+EXPORT_SYMBOL(tegra_dc_get_stride);
+
struct tegra_dc *tegra_dc_get_dc(unsigned idx)
{
if (idx < TEGRA_MAX_DC)
@@ -611,18 +513,6 @@ struct tegra_dc_win *tegra_dc_get_window(struct tegra_dc *dc, unsigned win)
}
EXPORT_SYMBOL(tegra_dc_get_window);
-static int get_topmost_window(u32 *depths, unsigned long *wins)
-{
- int idx, best = -1;
-
- for_each_set_bit(idx, wins, DC_N_WINDOWS) {
- if (best == -1 || depths[idx] < depths[best])
- best = idx;
- }
- clear_bit(best, wins);
- return best;
-}
-
bool tegra_dc_get_connected(struct tegra_dc *dc)
{
return dc->connected;
@@ -643,222 +533,6 @@ bool tegra_dc_hpd(struct tegra_dc *dc)
}
EXPORT_SYMBOL(tegra_dc_hpd);
-static u32 blend_topwin(u32 flags)
-{
- if (flags & TEGRA_WIN_FLAG_BLEND_COVERAGE)
- return BLEND(NOKEY, ALPHA, 0xff, 0xff);
- else if (flags & TEGRA_WIN_FLAG_BLEND_PREMULT)
- return BLEND(NOKEY, PREMULT, 0xff, 0xff);
- else
- return BLEND(NOKEY, FIX, 0xff, 0xff);
-}
-
-static u32 blend_2win(int idx, unsigned long behind_mask, u32* flags, int xy)
-{
- int other;
-
- for (other = 0; other < DC_N_WINDOWS; other++) {
- if (other != idx && (xy-- == 0))
- break;
- }
- if (BIT(other) & behind_mask)
- return blend_topwin(flags[idx]);
- else if (flags[other])
- return BLEND(NOKEY, DEPENDANT, 0x00, 0x00);
- else
- return BLEND(NOKEY, FIX, 0x00, 0x00);
-}
-
-static u32 blend_3win(int idx, unsigned long behind_mask, u32* flags)
-{
- unsigned long infront_mask;
- int first;
-
- infront_mask = ~(behind_mask | BIT(idx));
- infront_mask &= (BIT(DC_N_WINDOWS) - 1);
- first = ffs(infront_mask) - 1;
-
- if (!infront_mask)
- return blend_topwin(flags[idx]);
- else if (behind_mask && first != -1 && flags[first])
- return BLEND(NOKEY, DEPENDANT, 0x00, 0x00);
- else
- return BLEND(NOKEY, FIX, 0x0, 0x0);
-}
-
-static void tegra_dc_set_blending(struct tegra_dc *dc, struct tegra_dc_blend *blend)
-{
- unsigned long mask = BIT(DC_N_WINDOWS) - 1;
-
- while (mask) {
- int idx = get_topmost_window(blend->z, &mask);
-
- tegra_dc_writel(dc, WINDOW_A_SELECT << idx,
- DC_CMD_DISPLAY_WINDOW_HEADER);
- tegra_dc_writel(dc, BLEND(NOKEY, FIX, 0xff, 0xff),
- DC_WIN_BLEND_NOKEY);
- tegra_dc_writel(dc, BLEND(NOKEY, FIX, 0xff, 0xff),
- DC_WIN_BLEND_1WIN);
- tegra_dc_writel(dc, blend_2win(idx, mask, blend->flags, 0),
- DC_WIN_BLEND_2WIN_X);
- tegra_dc_writel(dc, blend_2win(idx, mask, blend->flags, 1),
- DC_WIN_BLEND_2WIN_Y);
- tegra_dc_writel(dc, blend_3win(idx, mask, blend->flags),
- DC_WIN_BLEND_3WIN_XY);
- }
-}
-
-static void tegra_dc_init_csc_defaults(struct tegra_dc_csc *csc)
-{
- csc->yof = 0x00f0;
- csc->kyrgb = 0x012a;
- csc->kur = 0x0000;
- csc->kvr = 0x0198;
- csc->kug = 0x039b;
- csc->kvg = 0x032f;
- csc->kub = 0x0204;
- csc->kvb = 0x0000;
-}
-
-static void tegra_dc_set_csc(struct tegra_dc *dc, struct tegra_dc_csc *csc)
-{
- tegra_dc_writel(dc, csc->yof, DC_WIN_CSC_YOF);
- tegra_dc_writel(dc, csc->kyrgb, DC_WIN_CSC_KYRGB);
- tegra_dc_writel(dc, csc->kur, DC_WIN_CSC_KUR);
- tegra_dc_writel(dc, csc->kvr, DC_WIN_CSC_KVR);
- tegra_dc_writel(dc, csc->kug, DC_WIN_CSC_KUG);
- tegra_dc_writel(dc, csc->kvg, DC_WIN_CSC_KVG);
- tegra_dc_writel(dc, csc->kub, DC_WIN_CSC_KUB);
- tegra_dc_writel(dc, csc->kvb, DC_WIN_CSC_KVB);
-}
-
-int tegra_dc_update_csc(struct tegra_dc *dc, int win_idx)
-{
- mutex_lock(&dc->lock);
-
- if (!dc->enabled) {
- mutex_unlock(&dc->lock);
- return -EFAULT;
- }
-
- tegra_dc_writel(dc, WINDOW_A_SELECT << win_idx,
- DC_CMD_DISPLAY_WINDOW_HEADER);
-
- tegra_dc_set_csc(dc, &dc->windows[win_idx].csc);
-
- mutex_unlock(&dc->lock);
-
- return 0;
-}
-EXPORT_SYMBOL(tegra_dc_update_csc);
-
-static void tegra_dc_init_lut_defaults(struct tegra_dc_lut *lut)
-{
- int i;
- for (i = 0; i < 256; i++)
- lut->r[i] = lut->g[i] = lut->b[i] = (u8)i;
-}
-
-static int tegra_dc_loop_lut(struct tegra_dc *dc,
- struct tegra_dc_win *win,
- int(*lambda)(struct tegra_dc *dc, int i, u32 rgb))
-{
- struct tegra_dc_lut *lut = &win->lut;
- struct tegra_dc_lut *global_lut = &dc->fb_lut;
- int i;
- for (i = 0; i < 256; i++) {
-
- u32 r = (u32)lut->r[i];
- u32 g = (u32)lut->g[i];
- u32 b = (u32)lut->b[i];
-
- if (!(win->ppflags & TEGRA_WIN_PPFLAG_CP_FBOVERRIDE)) {
- r = (u32)global_lut->r[r];
- g = (u32)global_lut->g[g];
- b = (u32)global_lut->b[b];
- }
-
- if (!lambda(dc, i, r | (g<<8) | (b<<16)))
- return 0;
- }
- return 1;
-}
-
-static int tegra_dc_lut_isdefaults_lambda(struct tegra_dc *dc, int i, u32 rgb)
-{
- if (rgb != (i | (i<<8) | (i<<16)))
- return 0;
- return 1;
-}
-
-static int tegra_dc_set_lut_setreg_lambda(struct tegra_dc *dc, int i, u32 rgb)
-{
- tegra_dc_writel(dc, rgb, DC_WIN_COLOR_PALETTE(i));
- return 1;
-}
-
-static void tegra_dc_set_lut(struct tegra_dc *dc, struct tegra_dc_win* win)
-{
- unsigned long val = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS);
-
- tegra_dc_loop_lut(dc, win, tegra_dc_set_lut_setreg_lambda);
-
- if (win->ppflags & TEGRA_WIN_PPFLAG_CP_ENABLE)
- val |= CP_ENABLE;
- else
- val &= ~CP_ENABLE;
-
- tegra_dc_writel(dc, val, DC_WIN_WIN_OPTIONS);
-}
-
-static int tegra_dc_update_winlut(struct tegra_dc *dc, int win_idx, int fbovr)
-{
- struct tegra_dc_win *win = &dc->windows[win_idx];
-
- mutex_lock(&dc->lock);
-
- if (!dc->enabled) {
- mutex_unlock(&dc->lock);
- return -EFAULT;
- }
-
- if (fbovr > 0)
- win->ppflags |= TEGRA_WIN_PPFLAG_CP_FBOVERRIDE;
- else if (fbovr == 0)
- win->ppflags &= ~TEGRA_WIN_PPFLAG_CP_FBOVERRIDE;
-
- if (!tegra_dc_loop_lut(dc, win, tegra_dc_lut_isdefaults_lambda))
- win->ppflags |= TEGRA_WIN_PPFLAG_CP_ENABLE;
- else
- win->ppflags &= ~TEGRA_WIN_PPFLAG_CP_ENABLE;
-
- tegra_dc_writel(dc, WINDOW_A_SELECT << win_idx,
- DC_CMD_DISPLAY_WINDOW_HEADER);
-
- tegra_dc_set_lut(dc, win);
-
- mutex_unlock(&dc->lock);
-
- tegra_dc_update_windows(&win, 1);
-
- return 0;
-}
-
-int tegra_dc_update_lut(struct tegra_dc *dc, int win_idx, int fboveride)
-{
- if (win_idx > -1)
- return tegra_dc_update_winlut(dc, win_idx, fboveride);
-
- for (win_idx = 0; win_idx < DC_N_WINDOWS; win_idx++) {
- int err = tegra_dc_update_winlut(dc, win_idx, fboveride);
- if (err)
- return err;
- }
-
- return 0;
-}
-EXPORT_SYMBOL(tegra_dc_update_lut);
-
static void tegra_dc_set_scaling_filter(struct tegra_dc *dc)
{
unsigned i;
@@ -876,510 +550,21 @@ static void tegra_dc_set_scaling_filter(struct tegra_dc *dc)
}
}
-static void tegra_dc_set_latency_allowance(struct tegra_dc *dc,
- struct tegra_dc_win *w)
-{
- /* windows A, B, C for first and second display */
- static const enum tegra_la_id la_id_tab[2][3] = {
- /* first display */
- { TEGRA_LA_DISPLAY_0A, TEGRA_LA_DISPLAY_0B,
- TEGRA_LA_DISPLAY_0C },
- /* second display */
- { TEGRA_LA_DISPLAY_0AB, TEGRA_LA_DISPLAY_0BB,
- TEGRA_LA_DISPLAY_0CB },
- };
- /* window B V-filter tap for first and second display. */
- static const enum tegra_la_id vfilter_tab[2] = {
- TEGRA_LA_DISPLAY_1B, TEGRA_LA_DISPLAY_1BB,
- };
- unsigned long bw;
-
- BUG_ON(dc->ndev->id >= ARRAY_SIZE(la_id_tab));
- BUG_ON(dc->ndev->id >= ARRAY_SIZE(vfilter_tab));
- BUG_ON(w->idx >= ARRAY_SIZE(*la_id_tab));
-
- bw = w->new_bandwidth;
-
- /* tegra_dc_get_bandwidth() treats V filter windows as double
- * bandwidth, but LA has a seperate client for V filter */
- if (w->idx == 1 && win_use_v_filter(w))
- bw /= 2;
-
- /* our bandwidth is in kbytes/sec, but LA takes MBps.
- * round up bandwidth to next 1MBps */
- bw = bw / 1000 + 1;
-
-#ifdef CONFIG_TEGRA_SILICON_PLATFORM
- tegra_set_latency_allowance(la_id_tab[dc->ndev->id][w->idx], bw);
- /* if window B, also set the 1B client for the 2-tap V filter. */
- if (w->idx == 1)
- tegra_set_latency_allowance(vfilter_tab[dc->ndev->id], bw);
-#endif
-
- w->bandwidth = w->new_bandwidth;
-}
-
-static unsigned int tegra_dc_windows_is_overlapped(struct tegra_dc_win *a,
- struct tegra_dc_win *b)
-{
- if (!WIN_IS_ENABLED(a) || !WIN_IS_ENABLED(b))
- return 0;
-
- /* because memory access to load the fifo can overlap, only care
- * if windows overlap vertically */
- return ((a->out_y + a->out_h > b->out_y) && (a->out_y <= b->out_y)) ||
- ((b->out_y + b->out_h > a->out_y) && (b->out_y <= a->out_y));
-}
-
-static unsigned long tegra_dc_find_max_bandwidth(struct tegra_dc_win *wins[],
- int n)
-{
- unsigned i;
- unsigned j;
- unsigned overlap_count;
- unsigned max_bw = 0;
-
- WARN_ONCE(n > 3, "Code assumes at most 3 windows, bandwidth is likely"
- "inaccurate.\n");
-
- /* If we had a large number of windows, we would compute adjacency
- * graph representing 2 window overlaps, find all cliques in the graph,
- * assign bandwidth to each clique, and then select the clique with
- * maximum bandwidth. But because we have at most 3 windows,
- * implementing proper Bron-Kerbosh algorithm would be an overkill,
- * brute force will suffice.
- *
- * Thus: find maximum bandwidth for either single or a pair of windows
- * and count number of window pair overlaps. If there are three
- * pairs, all 3 window overlap.
- */
-
- overlap_count = 0;
- for (i = 0; i < n; i++) {
- unsigned int bw1;
-
- if (wins[i] == NULL)
- continue;
- bw1 = wins[i]->new_bandwidth;
- if (bw1 > max_bw)
- /* Single window */
- max_bw = bw1;
-
- for (j = i + 1; j < n; j++) {
- if (wins[j] == NULL)
- continue;
- if (tegra_dc_windows_is_overlapped(wins[i], wins[j])) {
- unsigned int bw2 = wins[j]->new_bandwidth;
- if (bw1 + bw2 > max_bw)
- /* Window pair overlaps */
- max_bw = bw1 + bw2;
- overlap_count++;
- }
- }
- }
-
- if (overlap_count == 3)
- /* All three windows overlap */
- max_bw = wins[0]->new_bandwidth + wins[1]->new_bandwidth +
- wins[2]->new_bandwidth;
-
- return max_bw;
-}
-
-/*
- * Calculate peak EMC bandwidth for each enabled window =
- * pixel_clock * win_bpp * (use_v_filter ? 2 : 1)) * H_scale_factor *
- * (windows_tiling ? 2 : 1)
- *
- * note:
- * (*) We use 2 tap V filter, so need double BW if use V filter
- * (*) Tiling mode on T30 and DDR3 requires double BW
- *
- * return:
- * bandwidth in kBps
- */
-static unsigned long tegra_dc_calc_win_bandwidth(struct tegra_dc *dc,
- struct tegra_dc_win *w)
+void tegra_dc_host_suspend(struct tegra_dc *dc)
{
- unsigned long ret;
- int tiled_windows_bw_multiplier;
- unsigned long bpp;
-
- if (!WIN_IS_ENABLED(w))
- return 0;
-
- if (dfixed_trunc(w->w) == 0 || dfixed_trunc(w->h) == 0 ||
- w->out_w == 0 || w->out_h == 0)
- return 0;
-
- tiled_windows_bw_multiplier =
- tegra_mc_get_tiled_memory_bandwidth_multiplier();
-
- /* all of tegra's YUV formats(420 and 422) fetch 2 bytes per pixel,
- * but the size reported by tegra_dc_fmt_bpp for the planar version
- * is of the luma plane's size only. */
- bpp = tegra_dc_is_yuv_planar(w->fmt) ?
- 2 * tegra_dc_fmt_bpp(w->fmt) : tegra_dc_fmt_bpp(w->fmt);
- ret = dc->mode.pclk / 1000UL * bpp / 8 * (win_use_v_filter(w) ? 2 : 1)
- * dfixed_trunc(w->w) / w->out_w *
- (WIN_IS_TILED(w) ? tiled_windows_bw_multiplier : 1);
- /*
- * Assuming ~35% efficiency: i.e. if we calculate we need 70MBps, we
- * will request 200MBps from EMC.
- */
- ret = ret * 29 / 10;
-
- return ret;
+ tegra_dsi_host_suspend(dc);
+ tegra_dc_clk_disable(dc);
}
-static unsigned long tegra_dc_get_bandwidth(
- struct tegra_dc_win *windows[], int n)
-{
- int i;
-
- BUG_ON(n > DC_N_WINDOWS);
-
- /* emc rate and latency allowance both need to know per window
- * bandwidths */
- for (i = 0; i < n; i++) {
- struct tegra_dc_win *w = windows[i];
-
- if (w)
- w->new_bandwidth =
- tegra_dc_calc_win_bandwidth(w->dc, w);
- }
-
- return tegra_dc_find_max_bandwidth(windows, n);
+void tegra_dc_host_resume(struct tegra_dc *dc) {
+ tegra_dc_clk_enable(dc);
+ tegra_dsi_host_resume(dc);
}
-/* to save power, call when display memory clients would be idle */
-static void tegra_dc_clear_bandwidth(struct tegra_dc *dc)
-{
- trace_printk("%s:%s rate=%d\n", dc->ndev->name, __func__,
- dc->emc_clk_rate);
- if (tegra_is_clk_enabled(dc->emc_clk))
- clk_disable(dc->emc_clk);
- dc->emc_clk_rate = 0;
-}
-
-static void tegra_dc_program_bandwidth(struct tegra_dc *dc)
-{
- unsigned i;
-
- if (dc->emc_clk_rate != dc->new_emc_clk_rate) {
- /* going from 0 to non-zero */
- if (!dc->emc_clk_rate && !tegra_is_clk_enabled(dc->emc_clk))
- clk_enable(dc->emc_clk);
-
- dc->emc_clk_rate = dc->new_emc_clk_rate;
- clk_set_rate(dc->emc_clk, dc->emc_clk_rate);
-
- if (!dc->new_emc_clk_rate) /* going from non-zero to 0 */
- clk_disable(dc->emc_clk);
- }
-
- for (i = 0; i < DC_N_WINDOWS; i++) {
- struct tegra_dc_win *w = &dc->windows[i];
-
- if (w->bandwidth != w->new_bandwidth && w->new_bandwidth != 0)
- tegra_dc_set_latency_allowance(dc, w);
- trace_printk("%s:win%u bandwidth=%d\n", dc->ndev->name, w->idx,
- w->bandwidth);
- }
-}
-
-static int tegra_dc_set_dynamic_emc(struct tegra_dc_win *windows[], int n)
-{
- unsigned long new_rate;
- struct tegra_dc *dc;
-
- if (!use_dynamic_emc)
- return 0;
-
- dc = windows[0]->dc;
-
- /* calculate the new rate based on this POST */
- new_rate = tegra_dc_get_bandwidth(windows, n);
- if (WARN_ONCE(new_rate > (ULONG_MAX / 1000), "bandwidth maxed out\n"))
- new_rate = ULONG_MAX;
- else
- new_rate = EMC_BW_TO_FREQ(new_rate * 1000);
-
- if (tegra_dc_has_multiple_dc())
- new_rate = ULONG_MAX;
-
- trace_printk("%s:new_emc_clk_rate=%ld\n", dc->ndev->name, new_rate);
- dc->new_emc_clk_rate = new_rate;
-
- return 0;
-}
-
-static inline u32 compute_dda_inc(fixed20_12 in, unsigned out_int,
- bool v, unsigned Bpp)
-{
- /*
- * min(round((prescaled_size_in_pixels - 1) * 0x1000 /
- * (post_scaled_size_in_pixels - 1)), MAX)
- * Where the value of MAX is as follows:
- * For V_DDA_INCREMENT: 15.0 (0xF000)
- * For H_DDA_INCREMENT: 4.0 (0x4000) for 4 Bytes/pix formats.
- * 8.0 (0x8000) for 2 Bytes/pix formats.
- */
-
- fixed20_12 out = dfixed_init(out_int);
- u32 dda_inc;
- int max;
-
- if (v) {
- max = 15;
- } else {
- switch (Bpp) {
- default:
- WARN_ON_ONCE(1);
- /* fallthrough */
- case 4:
- max = 4;
- break;
- case 2:
- max = 8;
- break;
- }
- }
-
- out.full = max_t(u32, out.full - dfixed_const(1), dfixed_const(1));
- in.full -= dfixed_const(1);
-
- dda_inc = dfixed_div(in, out);
-
- dda_inc = min_t(u32, dda_inc, dfixed_const(max));
-
- return dda_inc;
-}
-
-static inline u32 compute_initial_dda(fixed20_12 in)
-{
- return dfixed_frac(in);
-}
-
-/* does not support updating windows on multiple dcs in one call */
-int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
+static inline void disable_dc_irq(unsigned int irq)
{
- struct tegra_dc *dc;
- unsigned long update_mask = GENERAL_ACT_REQ;
- unsigned long val;
- bool update_blend = false;
- int i;
-
- dc = windows[0]->dc;
-
- if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) {
- /* Acquire one_shot_lock to avoid race condition between
- * cancellation of old delayed work and schedule of new
- * delayed work. */
- mutex_lock(&dc->one_shot_lock);
- cancel_delayed_work_sync(&dc->one_shot_work);
- }
- mutex_lock(&dc->lock);
-
- if (!dc->enabled) {
- mutex_unlock(&dc->lock);
- if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
- mutex_unlock(&dc->one_shot_lock);
- return -EFAULT;
- }
-
- if (no_vsync)
- tegra_dc_writel(dc, WRITE_MUX_ACTIVE | READ_MUX_ACTIVE, DC_CMD_STATE_ACCESS);
- else
- tegra_dc_writel(dc, WRITE_MUX_ASSEMBLY | READ_MUX_ASSEMBLY, DC_CMD_STATE_ACCESS);
-
- for (i = 0; i < n; i++) {
- struct tegra_dc_win *win = windows[i];
- unsigned h_dda;
- unsigned v_dda;
- fixed20_12 h_offset, v_offset;
- bool invert_h = (win->flags & TEGRA_WIN_FLAG_INVERT_H) != 0;
- bool invert_v = (win->flags & TEGRA_WIN_FLAG_INVERT_V) != 0;
- bool yuv = tegra_dc_is_yuv(win->fmt);
- bool yuvp = tegra_dc_is_yuv_planar(win->fmt);
- unsigned Bpp = tegra_dc_fmt_bpp(win->fmt) / 8;
- /* Bytes per pixel of bandwidth, used for dda_inc calculation */
- unsigned Bpp_bw = Bpp * (yuvp ? 2 : 1);
- const bool filter_h = win_use_h_filter(win);
- const bool filter_v = win_use_v_filter(win);
-
- if (win->z != dc->blend.z[win->idx]) {
- dc->blend.z[win->idx] = win->z;
- update_blend = true;
- }
- if ((win->flags & TEGRA_WIN_BLEND_FLAGS_MASK) !=
- dc->blend.flags[win->idx]) {
- dc->blend.flags[win->idx] =
- win->flags & TEGRA_WIN_BLEND_FLAGS_MASK;
- update_blend = true;
- }
-
- tegra_dc_writel(dc, WINDOW_A_SELECT << win->idx,
- DC_CMD_DISPLAY_WINDOW_HEADER);
-
- if (!no_vsync)
- update_mask |= WIN_A_ACT_REQ << win->idx;
-
- if (!WIN_IS_ENABLED(win)) {
- tegra_dc_writel(dc, 0, DC_WIN_WIN_OPTIONS);
- continue;
- }
-
- tegra_dc_writel(dc, win->fmt & 0x1f, DC_WIN_COLOR_DEPTH);
- tegra_dc_writel(dc, win->fmt >> 6, DC_WIN_BYTE_SWAP);
-
- tegra_dc_writel(dc,
- V_POSITION(win->out_y) | H_POSITION(win->out_x),
- DC_WIN_POSITION);
- tegra_dc_writel(dc,
- V_SIZE(win->out_h) | H_SIZE(win->out_w),
- DC_WIN_SIZE);
- tegra_dc_writel(dc,
- V_PRESCALED_SIZE(dfixed_trunc(win->h)) |
- H_PRESCALED_SIZE(dfixed_trunc(win->w) * Bpp),
- DC_WIN_PRESCALED_SIZE);
-
- h_dda = compute_dda_inc(win->w, win->out_w, false, Bpp_bw);
- v_dda = compute_dda_inc(win->h, win->out_h, true, Bpp_bw);
- tegra_dc_writel(dc, V_DDA_INC(v_dda) | H_DDA_INC(h_dda),
- DC_WIN_DDA_INCREMENT);
- h_dda = compute_initial_dda(win->x);
- v_dda = compute_initial_dda(win->y);
- tegra_dc_writel(dc, h_dda, DC_WIN_H_INITIAL_DDA);
- tegra_dc_writel(dc, v_dda, DC_WIN_V_INITIAL_DDA);
-
- tegra_dc_writel(dc, 0, DC_WIN_BUF_STRIDE);
- tegra_dc_writel(dc, 0, DC_WIN_UV_BUF_STRIDE);
- tegra_dc_writel(dc,
- (unsigned long)win->phys_addr,
- DC_WINBUF_START_ADDR);
-
- if (!yuvp) {
- tegra_dc_writel(dc, win->stride, DC_WIN_LINE_STRIDE);
- } else {
- tegra_dc_writel(dc,
- (unsigned long)win->phys_addr_u,
- DC_WINBUF_START_ADDR_U);
- tegra_dc_writel(dc,
- (unsigned long)win->phys_addr_v,
- DC_WINBUF_START_ADDR_V);
- tegra_dc_writel(dc,
- LINE_STRIDE(win->stride) |
- UV_LINE_STRIDE(win->stride_uv),
- DC_WIN_LINE_STRIDE);
- }
-
- h_offset = win->x;
- if (invert_h) {
- h_offset.full += win->w.full - dfixed_const(1);
- }
-
- v_offset = win->y;
- if (invert_v) {
- v_offset.full += win->h.full - dfixed_const(1);
- }
-
- tegra_dc_writel(dc, dfixed_trunc(h_offset) * Bpp,
- DC_WINBUF_ADDR_H_OFFSET);
- tegra_dc_writel(dc, dfixed_trunc(v_offset),
- DC_WINBUF_ADDR_V_OFFSET);
-
- if (WIN_IS_TILED(win))
- tegra_dc_writel(dc,
- DC_WIN_BUFFER_ADDR_MODE_TILE |
- DC_WIN_BUFFER_ADDR_MODE_TILE_UV,
- DC_WIN_BUFFER_ADDR_MODE);
- else
- tegra_dc_writel(dc,
- DC_WIN_BUFFER_ADDR_MODE_LINEAR |
- DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV,
- DC_WIN_BUFFER_ADDR_MODE);
-
- val = WIN_ENABLE;
- if (yuv)
- val |= CSC_ENABLE;
- else if (tegra_dc_fmt_bpp(win->fmt) < 24)
- val |= COLOR_EXPAND;
-
- if (win->ppflags & TEGRA_WIN_PPFLAG_CP_ENABLE)
- val |= CP_ENABLE;
-
- if (filter_h)
- val |= H_FILTER_ENABLE;
- if (filter_v)
- val |= V_FILTER_ENABLE;
-
- if (invert_h)
- val |= H_DIRECTION_DECREMENT;
- if (invert_v)
- val |= V_DIRECTION_DECREMENT;
-
- tegra_dc_writel(dc, val, DC_WIN_WIN_OPTIONS);
-
- win->dirty = no_vsync ? 0 : 1;
-
- dev_dbg(&dc->ndev->dev, "%s():idx=%d z=%d x=%d y=%d w=%d h=%d "
- "out_x=%u out_y=%u out_w=%u out_h=%u "
- "fmt=%d yuvp=%d Bpp=%u filter_h=%d filter_v=%d",
- __func__, win->idx, win->z,
- dfixed_trunc(win->x), dfixed_trunc(win->y),
- dfixed_trunc(win->w), dfixed_trunc(win->h),
- win->out_x, win->out_y, win->out_w, win->out_h,
- win->fmt, yuvp, Bpp, filter_h, filter_v);
- trace_printk("%s:win%u in:%ux%u out:%ux%u fmt=%d\n",
- dc->ndev->name, win->idx, dfixed_trunc(win->w),
- dfixed_trunc(win->h), win->out_w, win->out_h, win->fmt);
- }
-
- if (update_blend) {
- tegra_dc_set_blending(dc, &dc->blend);
- for (i = 0; i < DC_N_WINDOWS; i++) {
- if (!no_vsync)
- dc->windows[i].dirty = 1;
- update_mask |= WIN_A_ACT_REQ << i;
- }
- }
-
- tegra_dc_set_dynamic_emc(windows, n);
-
- tegra_dc_writel(dc, update_mask << 8, DC_CMD_STATE_CONTROL);
-
- tegra_dc_writel(dc, FRAME_END_INT | V_BLANK_INT, DC_CMD_INT_STATUS);
- if (!no_vsync) {
- val = tegra_dc_readl(dc, DC_CMD_INT_MASK);
- val |= (FRAME_END_INT | V_BLANK_INT | ALL_UF_INT);
- tegra_dc_writel(dc, val, DC_CMD_INT_MASK);
- } else {
- val = tegra_dc_readl(dc, DC_CMD_INT_MASK);
- val &= ~(FRAME_END_INT | V_BLANK_INT | ALL_UF_INT);
- tegra_dc_writel(dc, val, DC_CMD_INT_MASK);
- }
-
- if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
- schedule_delayed_work(&dc->one_shot_work,
- msecs_to_jiffies(dc->one_shot_delay_ms));
-
- /* update EMC clock if calculated bandwidth has changed */
- tegra_dc_program_bandwidth(dc);
-
- if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
- update_mask |= NC_HOST_TRIG;
-
- tegra_dc_writel(dc, update_mask, DC_CMD_STATE_CONTROL);
- trace_printk("%s:update_mask=%#lx\n", dc->ndev->name, update_mask);
-
- mutex_unlock(&dc->lock);
- if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
- mutex_unlock(&dc->one_shot_lock);
-
- return 0;
+ disable_irq(irq);
}
-EXPORT_SYMBOL(tegra_dc_update_windows);
u32 tegra_dc_get_syncpt_id(const struct tegra_dc *dc, int i)
{
@@ -1392,7 +577,7 @@ u32 tegra_dc_incr_syncpt_max(struct tegra_dc *dc, int i)
u32 max;
mutex_lock(&dc->lock);
- max = nvhost_syncpt_incr_max(&nvhost_get_host(dc->ndev)->syncpt,
+ max = nvhost_syncpt_incr_max_ext(dc->ndev,
dc->syncpt[i].id, ((dc->enabled) ? 1 : 0));
dc->syncpt[i].max = max;
mutex_unlock(&dc->lock);
@@ -1406,491 +591,11 @@ void tegra_dc_incr_syncpt_min(struct tegra_dc *dc, int i, u32 val)
if ( dc->enabled )
while (dc->syncpt[i].min < val) {
dc->syncpt[i].min++;
- nvhost_syncpt_cpu_incr(
- &nvhost_get_host(dc->ndev)->syncpt,
- dc->syncpt[i].id);
+ nvhost_syncpt_cpu_incr_ext(dc->ndev, dc->syncpt[i].id);
}
mutex_unlock(&dc->lock);
}
-static bool tegra_dc_windows_are_clean(struct tegra_dc_win *windows[],
- int n)
-{
- int i;
-
- for (i = 0; i < n; i++) {
- if (windows[i]->dirty)
- return false;
- }
-
- return true;
-}
-
-/* does not support syncing windows on multiple dcs in one call */
-int tegra_dc_sync_windows(struct tegra_dc_win *windows[], int n)
-{
- int ret;
- if (n < 1 || n > DC_N_WINDOWS)
- return -EINVAL;
-
- if (!windows[0]->dc->enabled)
- return -EFAULT;
-
-#ifdef CONFIG_TEGRA_SIMULATION_PLATFORM
- /* Don't want to timeout on simulator */
- ret = wait_event_interruptible(windows[0]->dc->wq,
- tegra_dc_windows_are_clean(windows, n));
-#else
- trace_printk("%s:Before wait_event_interruptible_timeout\n",
- windows[0]->dc->ndev->name);
- ret = wait_event_interruptible_timeout(windows[0]->dc->wq,
- tegra_dc_windows_are_clean(windows, n),
- HZ);
- trace_printk("%s:After wait_event_interruptible_timeout\n",
- windows[0]->dc->ndev->name);
-#endif
- return ret;
-}
-EXPORT_SYMBOL(tegra_dc_sync_windows);
-
-static unsigned long tegra_dc_clk_get_rate(struct tegra_dc *dc)
-{
-#ifdef CONFIG_TEGRA_SILICON_PLATFORM
- return clk_get_rate(dc->clk);
-#else
- return 27000000;
-#endif
-}
-
-static unsigned long tegra_dc_pclk_round_rate(struct tegra_dc *dc, int pclk)
-{
- unsigned long rate;
- unsigned long div;
-
- rate = tegra_dc_clk_get_rate(dc);
-
- div = DIV_ROUND_CLOSEST(rate * 2, pclk);
-
- if (div < 2)
- return 0;
-
- return rate * 2 / div;
-}
-
-static unsigned long tegra_dc_pclk_predict_rate(struct clk *parent, int pclk)
-{
- unsigned long rate;
- unsigned long div;
-
- rate = clk_get_rate(parent);
-
- div = DIV_ROUND_CLOSEST(rate * 2, pclk);
-
- if (div < 2)
- return 0;
-
- return rate * 2 / div;
-}
-
-void tegra_dc_setup_clk(struct tegra_dc *dc, struct clk *clk)
-{
- int pclk;
-
- if (dc->out->type == TEGRA_DC_OUT_RGB) {
- unsigned long rate;
- struct clk *parent_clk =
- clk_get_sys(NULL, dc->out->parent_clk ? : "pll_p");
-
- if (dc->out->parent_clk_backup &&
- (parent_clk == clk_get_sys(NULL, "pll_p"))) {
- rate = tegra_dc_pclk_predict_rate(
- parent_clk, dc->mode.pclk);
- /* use pll_d as last resort */
- if (rate < (dc->mode.pclk / 100 * 99) ||
- rate > (dc->mode.pclk / 100 * 109))
- parent_clk = clk_get_sys(
- NULL, dc->out->parent_clk_backup);
- }
-
- if (clk_get_parent(clk) != parent_clk)
- clk_set_parent(clk, parent_clk);
-
- if (parent_clk != clk_get_sys(NULL, "pll_p")) {
- struct clk *base_clk = clk_get_parent(parent_clk);
-
- /* Assuming either pll_d or pll_d2 is used */
- rate = dc->mode.pclk * 2;
-
- if (rate != clk_get_rate(base_clk))
- clk_set_rate(base_clk, rate);
- }
- }
-
- if (dc->out->type == TEGRA_DC_OUT_HDMI) {
- unsigned long rate;
- struct clk *parent_clk =
- clk_get_sys(NULL, dc->out->parent_clk ? : "pll_d_out0");
- struct clk *base_clk = clk_get_parent(parent_clk);
-
- /*
- * Providing dynamic frequency rate setting for T20/T30 HDMI.
- * The required rate needs to be setup at 4x multiplier,
- * as out0 is 1/2 of the actual PLL output.
- */
-
- rate = dc->mode.pclk * 4;
- if (rate != clk_get_rate(base_clk))
- clk_set_rate(base_clk, rate);
-
- if (clk_get_parent(clk) != parent_clk)
- clk_set_parent(clk, parent_clk);
- }
-
- if (dc->out->type == TEGRA_DC_OUT_DSI) {
- unsigned long rate;
- struct clk *parent_clk;
- struct clk *base_clk;
-
- if (clk == dc->clk) {
- parent_clk = clk_get_sys(NULL,
- dc->out->parent_clk ? : "pll_d_out0");
- base_clk = clk_get_parent(parent_clk);
- tegra_clk_cfg_ex(base_clk,
- TEGRA_CLK_PLLD_DSI_OUT_ENB, 1);
- } else {
- if (dc->pdata->default_out->dsi->dsi_instance) {
- parent_clk = clk_get_sys(NULL,
- dc->out->parent_clk ? : "pll_d2_out0");
- base_clk = clk_get_parent(parent_clk);
- tegra_clk_cfg_ex(base_clk,
- TEGRA_CLK_PLLD_CSI_OUT_ENB, 1);
- } else {
- parent_clk = clk_get_sys(NULL,
- dc->out->parent_clk ? : "pll_d_out0");
- base_clk = clk_get_parent(parent_clk);
- tegra_clk_cfg_ex(base_clk,
- TEGRA_CLK_PLLD_DSI_OUT_ENB, 1);
- }
- }
-
- rate = dc->mode.pclk * dc->shift_clk_div * 2;
- if (rate != clk_get_rate(base_clk))
- clk_set_rate(base_clk, rate);
-
- if (clk_get_parent(clk) != parent_clk)
- clk_set_parent(clk, parent_clk);
- }
-
- pclk = tegra_dc_pclk_round_rate(dc, dc->mode.pclk);
- tegra_dvfs_set_rate(clk, pclk);
-}
-
-/* return non-zero if constraint is violated */
-static int calc_h_ref_to_sync(const struct tegra_dc_mode *mode, int *href)
-{
- long a, b;
-
- /* Constraint 5: H_REF_TO_SYNC >= 0 */
- a = 0;
-
- /* Constraint 6: H_FRONT_PORT >= (H_REF_TO_SYNC + 1) */
- b = mode->h_front_porch - 1;
-
- /* Constraint 1: H_REF_TO_SYNC + H_SYNC_WIDTH + H_BACK_PORCH > 11 */
- if (a + mode->h_sync_width + mode->h_back_porch <= 11)
- a = 1 + 11 - mode->h_sync_width - mode->h_back_porch;
- /* check Constraint 1 and 6 */
- if (a > b)
- return 1;
-
- /* Constraint 4: H_SYNC_WIDTH >= 1 */
- if (mode->h_sync_width < 1)
- return 4;
-
- /* Constraint 7: H_DISP_ACTIVE >= 16 */
- if (mode->h_active < 16)
- return 7;
-
- if (href) {
- if (b > a && a % 2)
- *href = a + 1; /* use smallest even value */
- else
- *href = a; /* even or only possible value */
- }
-
- return 0;
-}
-
-static int calc_v_ref_to_sync(const struct tegra_dc_mode *mode, int *vref)
-{
- long a;
- a = 1; /* Constraint 5: V_REF_TO_SYNC >= 1 */
-
- /* Constraint 2: V_REF_TO_SYNC + V_SYNC_WIDTH + V_BACK_PORCH > 1 */
- if (a + mode->v_sync_width + mode->v_back_porch <= 1)
- a = 1 + 1 - mode->v_sync_width - mode->v_back_porch;
-
- /* Constraint 6 */
- if (mode->v_front_porch < a + 1)
- a = mode->v_front_porch - 1;
-
- /* Constraint 4: V_SYNC_WIDTH >= 1 */
- if (mode->v_sync_width < 1)
- return 4;
-
- /* Constraint 7: V_DISP_ACTIVE >= 16 */
- if (mode->v_active < 16)
- return 7;
-
- if (vref)
- *vref = a;
- return 0;
-}
-
-static int calc_ref_to_sync(struct tegra_dc_mode *mode)
-{
- int ret;
- ret = calc_h_ref_to_sync(mode, &mode->h_ref_to_sync);
- if (ret)
- return ret;
- ret = calc_v_ref_to_sync(mode, &mode->v_ref_to_sync);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static bool check_ref_to_sync(struct tegra_dc_mode *mode)
-{
- /* Constraint 1: H_REF_TO_SYNC + H_SYNC_WIDTH + H_BACK_PORCH > 11. */
- if (mode->h_ref_to_sync + mode->h_sync_width + mode->h_back_porch <= 11)
- return false;
-
- /* Constraint 2: V_REF_TO_SYNC + V_SYNC_WIDTH + V_BACK_PORCH > 1. */
- if (mode->v_ref_to_sync + mode->v_sync_width + mode->v_back_porch <= 1)
- return false;
-
- /* Constraint 3: V_FRONT_PORCH + V_SYNC_WIDTH + V_BACK_PORCH > 1
- * (vertical blank). */
- if (mode->v_front_porch + mode->v_sync_width + mode->v_back_porch <= 1)
- return false;
-
- /* Constraint 4: V_SYNC_WIDTH >= 1; H_SYNC_WIDTH >= 1. */
- if (mode->v_sync_width < 1 || mode->h_sync_width < 1)
- return false;
-
- /* Constraint 5: V_REF_TO_SYNC >= 1; H_REF_TO_SYNC >= 0. */
- if (mode->v_ref_to_sync < 1 || mode->h_ref_to_sync < 0)
- return false;
-
- /* Constraint 6: V_FRONT_PORT >= (V_REF_TO_SYNC + 1);
- * H_FRONT_PORT >= (H_REF_TO_SYNC + 1). */
- if (mode->v_front_porch < mode->v_ref_to_sync + 1 ||
- mode->h_front_porch < mode->h_ref_to_sync + 1)
- return false;
-
- /* Constraint 7: H_DISP_ACTIVE >= 16; V_DISP_ACTIVE >= 16. */
- if (mode->h_active < 16 || mode->v_active < 16)
- return false;
-
- return true;
-}
-
-#ifdef DEBUG
-/* return in 1000ths of a Hertz */
-static int calc_refresh(const struct tegra_dc_mode *m)
-{
- long h_total, v_total, refresh;
- h_total = m->h_active + m->h_front_porch + m->h_back_porch +
- m->h_sync_width;
- v_total = m->v_active + m->v_front_porch + m->v_back_porch +
- m->v_sync_width;
- refresh = m->pclk / h_total;
- refresh *= 1000;
- refresh /= v_total;
- return refresh;
-}
-
-static void print_mode(struct tegra_dc *dc,
- const struct tegra_dc_mode *mode, const char *note)
-{
- if (mode) {
- int refresh = calc_refresh(dc, mode);
- dev_info(&dc->ndev->dev, "%s():MODE:%dx%d@%d.%03uHz pclk=%d\n",
- note ? note : "",
- mode->h_active, mode->v_active,
- refresh / 1000, refresh % 1000,
- mode->pclk);
- }
-}
-#else /* !DEBUG */
-static inline void print_mode(struct tegra_dc *dc,
- const struct tegra_dc_mode *mode, const char *note) { }
-#endif /* DEBUG */
-
-static inline void enable_dc_irq(unsigned int irq)
-{
-#ifndef CONFIG_TEGRA_FPGA_PLATFORM
- enable_irq(irq);
-#else
- /* Always disable DC interrupts on FPGA. */
- disable_irq(irq);
-#endif
-}
-
-static inline void disable_dc_irq(unsigned int irq)
-{
- disable_irq(irq);
-}
-
-static int tegra_dc_program_mode(struct tegra_dc *dc, struct tegra_dc_mode *mode)
-{
- unsigned long val;
- unsigned long rate;
- unsigned long div;
- unsigned long pclk;
-
- print_mode(dc, mode, __func__);
-
- /* use default EMC rate when switching modes */
- dc->new_emc_clk_rate = tegra_dc_get_default_emc_clk_rate(dc);
- tegra_dc_program_bandwidth(dc);
-
- tegra_dc_writel(dc, 0x0, DC_DISP_DISP_TIMING_OPTIONS);
- tegra_dc_writel(dc, mode->h_ref_to_sync | (mode->v_ref_to_sync << 16),
- DC_DISP_REF_TO_SYNC);
- tegra_dc_writel(dc, mode->h_sync_width | (mode->v_sync_width << 16),
- DC_DISP_SYNC_WIDTH);
- tegra_dc_writel(dc, mode->h_back_porch | (mode->v_back_porch << 16),
- DC_DISP_BACK_PORCH);
- tegra_dc_writel(dc, mode->h_active | (mode->v_active << 16),
- DC_DISP_DISP_ACTIVE);
- tegra_dc_writel(dc, mode->h_front_porch | (mode->v_front_porch << 16),
- DC_DISP_FRONT_PORCH);
-
- tegra_dc_writel(dc, DE_SELECT_ACTIVE | DE_CONTROL_NORMAL,
- DC_DISP_DATA_ENABLE_OPTIONS);
-
- /* TODO: MIPI/CRT/HDMI clock cals */
-
- val = DISP_DATA_FORMAT_DF1P1C;
-
- if (dc->out->align == TEGRA_DC_ALIGN_MSB)
- val |= DISP_DATA_ALIGNMENT_MSB;
- else
- val |= DISP_DATA_ALIGNMENT_LSB;
-
- if (dc->out->order == TEGRA_DC_ORDER_RED_BLUE)
- val |= DISP_DATA_ORDER_RED_BLUE;
- else
- val |= DISP_DATA_ORDER_BLUE_RED;
-
- tegra_dc_writel(dc, val, DC_DISP_DISP_INTERFACE_CONTROL);
-
- rate = tegra_dc_clk_get_rate(dc);
-
- pclk = tegra_dc_pclk_round_rate(dc, mode->pclk);
- trace_printk("%s:pclk=%ld\n", dc->ndev->name, pclk);
- if (pclk < (mode->pclk / 100 * 99) ||
- pclk > (mode->pclk / 100 * 109)) {
- dev_err(&dc->ndev->dev,
- "can't divide %ld clock to %d -1/+9%% %ld %d %d\n",
- rate, mode->pclk,
- pclk, (mode->pclk / 100 * 99),
- (mode->pclk / 100 * 109));
- return -EINVAL;
- }
-
- div = (rate * 2 / pclk) - 2;
- trace_printk("%s:div=%ld\n", dc->ndev->name, div);
-
- tegra_dc_writel(dc, 0x00010001,
- DC_DISP_SHIFT_CLOCK_OPTIONS);
- tegra_dc_writel(dc, PIXEL_CLK_DIVIDER_PCD1 | SHIFT_CLK_DIVIDER(div),
- DC_DISP_DISP_CLOCK_CONTROL);
-
-#ifdef CONFIG_SWITCH
- switch_set_state(&dc->modeset_switch,
- (mode->h_active << 16) | mode->v_active);
-#endif
-
- tegra_dc_writel(dc, GENERAL_UPDATE, DC_CMD_STATE_CONTROL);
- tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
-
- print_mode_info(dc, dc->mode);
- return 0;
-}
-
-
-int tegra_dc_set_mode(struct tegra_dc *dc, const struct tegra_dc_mode *mode)
-{
- memcpy(&dc->mode, mode, sizeof(dc->mode));
-
- print_mode(dc, mode, __func__);
-
- return 0;
-}
-EXPORT_SYMBOL(tegra_dc_set_mode);
-
-int tegra_dc_set_fb_mode(struct tegra_dc *dc,
- const struct fb_videomode *fbmode, bool stereo_mode)
-{
- struct tegra_dc_mode mode;
-
- if (!fbmode->pixclock)
- return -EINVAL;
-
- mode.pclk = PICOS2KHZ(fbmode->pixclock) * 1000;
- mode.h_sync_width = fbmode->hsync_len;
- mode.v_sync_width = fbmode->vsync_len;
- mode.h_back_porch = fbmode->left_margin;
- mode.v_back_porch = fbmode->upper_margin;
- mode.h_active = fbmode->xres;
- mode.v_active = fbmode->yres;
- mode.h_front_porch = fbmode->right_margin;
- mode.v_front_porch = fbmode->lower_margin;
- mode.stereo_mode = stereo_mode;
- if (dc->out->type == TEGRA_DC_OUT_HDMI) {
- /* HDMI controller requires h_ref=1, v_ref=1 */
- mode.h_ref_to_sync = 1;
- mode.v_ref_to_sync = 1;
- } else {
- calc_ref_to_sync(&mode);
- }
- if (!check_ref_to_sync(&mode)) {
- dev_err(&dc->ndev->dev,
- "Display timing doesn't meet restrictions.\n");
- return -EINVAL;
- }
- dev_info(&dc->ndev->dev, "Using mode %dx%d pclk=%d href=%d vref=%d\n",
- mode.h_active, mode.v_active, mode.pclk,
- mode.h_ref_to_sync, mode.v_ref_to_sync
- );
-
-#ifndef CONFIG_TEGRA_HDMI_74MHZ_LIMIT
- /* Double the pixel clock and update v_active only for frame packed mode */
- if (mode.stereo_mode) {
- mode.pclk *= 2;
- /* total v_active = yres*2 + activespace */
- mode.v_active = fbmode->yres*2 +
- fbmode->vsync_len +
- fbmode->upper_margin +
- fbmode->lower_margin;
- }
-#endif
-
- mode.flags = 0;
-
- if (!(fbmode->sync & FB_SYNC_HOR_HIGH_ACT))
- mode.flags |= TEGRA_DC_MODE_FLAG_NEG_H_SYNC;
-
- if (!(fbmode->sync & FB_SYNC_VERT_HIGH_ACT))
- mode.flags |= TEGRA_DC_MODE_FLAG_NEG_V_SYNC;
-
- return tegra_dc_set_mode(dc, &mode);
-}
-EXPORT_SYMBOL(tegra_dc_set_fb_mode);
-
void
tegra_dc_config_pwm(struct tegra_dc *dc, struct tegra_dc_pwm_params *cfg)
{
@@ -1904,6 +609,9 @@ tegra_dc_config_pwm(struct tegra_dc *dc, struct tegra_dc_pwm_params *cfg)
return;
}
+ if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_LP_MODE)
+ tegra_dc_host_resume(dc);
+
ctrl = ((cfg->period << PM_PERIOD_SHIFT) |
(cfg->clk_div << PM_CLK_DIVIDER_SHIFT) |
cfg->clk_select);
@@ -1912,11 +620,6 @@ tegra_dc_config_pwm(struct tegra_dc *dc, struct tegra_dc_pwm_params *cfg)
cmd_state = tegra_dc_readl(dc, DC_CMD_STATE_ACCESS);
tegra_dc_writel(dc, (cmd_state | (1 << 2)), DC_CMD_STATE_ACCESS);
- if (cfg->switch_to_sfio && cfg->gpio_conf_to_sfio)
- cfg->switch_to_sfio(cfg->gpio_conf_to_sfio);
- else
- dev_err(&dc->ndev->dev, "Error: Need gpio_conf_to_sfio\n");
-
switch (cfg->which_pwm) {
case TEGRA_PWM_PM0:
/* Select the LM0 on PM0 */
@@ -2011,11 +714,27 @@ void tegra_dc_set_out_pin_polars(struct tegra_dc *dc,
tegra_dc_writel(dc, pol3, DC_COM_PIN_OUTPUT_POLARITY3);
}
+static struct tegra_dc_mode *tegra_dc_get_override_mode(struct tegra_dc *dc)
+{
+ if (dc->out->type == TEGRA_DC_OUT_RGB ||
+ dc->out->type == TEGRA_DC_OUT_HDMI ||
+ dc->out->type == TEGRA_DC_OUT_DSI)
+ return override_disp_mode[dc->out->type].pclk ?
+ &override_disp_mode[dc->out->type] : NULL;
+ else
+ return NULL;
+}
+
static void tegra_dc_set_out(struct tegra_dc *dc, struct tegra_dc_out *out)
{
+ struct tegra_dc_mode *mode;
+
dc->out = out;
+ mode = tegra_dc_get_override_mode(dc);
- if (out->n_modes > 0)
+ if (mode)
+ tegra_dc_set_mode(dc, mode);
+ else if (out->n_modes > 0)
tegra_dc_set_mode(dc, &dc->out->modes[0]);
switch (out->type) {
@@ -2093,7 +812,7 @@ u32 tegra_dc_read_checksum_latched(struct tegra_dc *dc)
{
int crc = 0;
- if(!dc) {
+ if (!dc) {
dev_err(&dc->ndev->dev, "Failed to get dc.\n");
goto crc_error;
}
@@ -2107,6 +826,28 @@ crc_error:
return crc;
}
+static bool tegra_dc_windows_are_dirty(struct tegra_dc *dc)
+{
+#ifndef CONFIG_TEGRA_SIMULATION_PLATFORM
+ u32 val;
+
+ val = tegra_dc_readl(dc, DC_CMD_STATE_CONTROL);
+ if (val & (WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ))
+ return true;
+#endif
+ return false;
+}
+
+static inline void enable_dc_irq(unsigned int irq)
+{
+#ifndef CONFIG_TEGRA_FPGA_PLATFORM
+ enable_irq(irq);
+#else
+ /* Always disable DC interrupts on FPGA. */
+ disable_irq(irq);
+#endif
+}
+
static void tegra_dc_vblank(struct work_struct *work)
{
struct tegra_dc *dc = container_of(work, struct tegra_dc, vblank_work);
@@ -2114,9 +855,36 @@ static void tegra_dc_vblank(struct work_struct *work)
mutex_lock(&dc->lock);
+ if (!dc->enabled) {
+ mutex_unlock(&dc->lock);
+ return;
+ }
+
+ /* use the new frame's bandwidth setting instead of max(current, new),
+ * skip this if we're using tegra_dc_one_shot_worker() */
+ if (!(dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE))
+ tegra_dc_program_bandwidth(dc, true);
+
+ /* Clear the V_BLANK_FLIP bit of vblank ref-count if update is clean. */
+ if (!tegra_dc_windows_are_dirty(dc))
+ clear_bit(V_BLANK_FLIP, &dc->vblank_ref_count);
+
/* Update the SD brightness */
- if (dc->enabled && dc->out->sd_settings)
+ if (dc->enabled && dc->out->sd_settings) {
nvsd_updated = nvsd_update_brightness(dc);
+ /* Ref-count vblank if nvsd is on-going. Otherwise, clean the
+ * V_BLANK_NVSD bit of vblank ref-count. */
+ if (nvsd_updated) {
+ set_bit(V_BLANK_NVSD, &dc->vblank_ref_count);
+ tegra_dc_unmask_interrupt(dc, V_BLANK_INT);
+ } else {
+ clear_bit(V_BLANK_NVSD, &dc->vblank_ref_count);
+ }
+ }
+
+ /* Mask vblank interrupt if ref-count is zero. */
+ if (!dc->vblank_ref_count)
+ tegra_dc_mask_interrupt(dc, V_BLANK_INT);
mutex_unlock(&dc->lock);
@@ -2131,30 +899,18 @@ static void tegra_dc_vblank(struct work_struct *work)
}
}
-/* Must acquire dc lock and dc one-shot lock before invoking this function.
- * Acquire dc one-shot lock first and then dc lock. */
-void tegra_dc_host_trigger(struct tegra_dc *dc)
-{
- /* We release the lock here to prevent deadlock between
- * cancel_delayed_work_sync and one-shot work. */
- mutex_unlock(&dc->lock);
-
- cancel_delayed_work_sync(&dc->one_shot_work);
- mutex_lock(&dc->lock);
-
- schedule_delayed_work(&dc->one_shot_work,
- msecs_to_jiffies(dc->one_shot_delay_ms));
- tegra_dc_program_bandwidth(dc);
- tegra_dc_writel(dc, NC_HOST_TRIG, DC_CMD_STATE_CONTROL);
-}
-
static void tegra_dc_one_shot_worker(struct work_struct *work)
{
struct tegra_dc *dc = container_of(
to_delayed_work(work), struct tegra_dc, one_shot_work);
mutex_lock(&dc->lock);
+
/* memory client has gone idle */
tegra_dc_clear_bandwidth(dc);
+
+ if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_LP_MODE)
+ tegra_dc_host_suspend(dc);
+
mutex_unlock(&dc->lock);
}
@@ -2204,6 +960,26 @@ static void tegra_dc_underflow_handler(struct tegra_dc *dc)
dc->ndev->name, (65 + i));
}
#endif
+#ifdef CONFIG_ARCH_TEGRA_3x_SOC
+ if (dc->windows[i].underflows > 4) {
+ printk("%s:dc in underflow state."
+ " enable UF_LINE_FLUSH to clear up\n",
+ __func__);
+ tegra_dc_writel(dc, UF_LINE_FLUSH,
+ DC_DISP_DISP_MISC_CONTROL);
+ tegra_dc_writel(dc, GENERAL_UPDATE,
+ DC_CMD_STATE_CONTROL);
+ tegra_dc_writel(dc, GENERAL_ACT_REQ,
+ DC_CMD_STATE_CONTROL);
+
+ tegra_dc_writel(dc, 0,
+ DC_DISP_DISP_MISC_CONTROL);
+ tegra_dc_writel(dc, GENERAL_UPDATE,
+ DC_CMD_STATE_CONTROL);
+ tegra_dc_writel(dc, GENERAL_ACT_REQ,
+ DC_CMD_STATE_CONTROL);
+ }
+#endif
} else {
dc->windows[i].underflows = 0;
}
@@ -2218,63 +994,6 @@ static void tegra_dc_underflow_handler(struct tegra_dc *dc)
}
#ifndef CONFIG_TEGRA_FPGA_PLATFORM
-static bool tegra_dc_windows_are_dirty(struct tegra_dc *dc)
-{
-#ifndef CONFIG_TEGRA_SIMULATION_PLATFORM
- u32 val;
-
- val = tegra_dc_readl(dc, DC_CMD_STATE_CONTROL);
- if (val & (WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE))
- return true;
-#endif
- return false;
-}
-
-static void tegra_dc_trigger_windows(struct tegra_dc *dc)
-{
- u32 val, i;
- u32 completed = 0;
- u32 dirty = 0;
-
- val = tegra_dc_readl(dc, DC_CMD_STATE_CONTROL);
- for (i = 0; i < DC_N_WINDOWS; i++) {
-#ifdef CONFIG_TEGRA_SIMULATION_PLATFORM
- /* FIXME: this is not needed when the simulator
- clears WIN_x_UPDATE bits as in HW */
- dc->windows[i].dirty = 0;
- completed = 1;
-#else
- if (!(val & (WIN_A_UPDATE << i))) {
- dc->windows[i].dirty = 0;
- completed = 1;
- } else {
- dirty = 1;
- }
-#endif
- }
-
- if (!dirty) {
- val = tegra_dc_readl(dc, DC_CMD_INT_MASK);
- if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
- val &= ~V_BLANK_INT;
- else
- val &= ~FRAME_END_INT;
- tegra_dc_writel(dc, val, DC_CMD_INT_MASK);
- }
-
- if (completed) {
- if (!dirty) {
- /* With the last completed window, go ahead
- and enable the vblank interrupt for nvsd. */
- val = tegra_dc_readl(dc, DC_CMD_INT_MASK);
- val |= V_BLANK_INT;
- tegra_dc_writel(dc, val, DC_CMD_INT_MASK);
- }
-
- wake_up(&dc->wq);
- }
-}
-
static void tegra_dc_one_shot_irq(struct tegra_dc *dc, unsigned long status)
{
if (status & V_BLANK_INT) {
@@ -2282,7 +1001,7 @@ static void tegra_dc_one_shot_irq(struct tegra_dc *dc, unsigned long status)
tegra_dc_trigger_windows(dc);
/* Schedule any additional bottom-half vblank actvities. */
- schedule_work(&dc->vblank_work);
+ queue_work(system_freezable_wq, &dc->vblank_work);
}
if (status & FRAME_END_INT) {
@@ -2294,19 +1013,9 @@ static void tegra_dc_one_shot_irq(struct tegra_dc *dc, unsigned long status)
static void tegra_dc_continuous_irq(struct tegra_dc *dc, unsigned long status)
{
- if (status & V_BLANK_INT) {
- /* Schedule any additional bottom-half vblank actvities. */
- schedule_work(&dc->vblank_work);
-
- /* All windows updated. Mask subsequent V_BLANK interrupts */
- if (!tegra_dc_windows_are_dirty(dc)) {
- u32 val;
-
- val = tegra_dc_readl(dc, DC_CMD_INT_MASK);
- val &= ~V_BLANK_INT;
- tegra_dc_writel(dc, val, DC_CMD_INT_MASK);
- }
- }
+ /* Schedule any additional bottom-half vblank actvities. */
+ if (status & V_BLANK_INT)
+ queue_work(system_freezable_wq, &dc->vblank_work);
if (status & FRAME_END_INT) {
/* Mark the frame_end as complete. */
@@ -2326,7 +1035,7 @@ static irqreturn_t tegra_dc_irq(int irq, void *ptr)
unsigned long underflow_mask;
u32 val;
- if (!nvhost_module_powered(nvhost_get_host(dc->ndev)->dev)) {
+ if (!nvhost_module_powered_ext(nvhost_get_parent(dc->ndev))) {
WARN(1, "IRQ when DC not powered!\n");
tegra_dc_io_start(dc);
status = tegra_dc_readl(dc, DC_CMD_INT_STATUS);
@@ -2509,7 +1218,9 @@ static int tegra_dc_init(struct tegra_dc *dc)
tegra_dc_writel(dc, 0x0001c700, DC_CMD_INT_POLARITY);
tegra_dc_writel(dc, 0x00202020, DC_DISP_MEM_HIGH_PRIORITY);
tegra_dc_writel(dc, 0x00010101, DC_DISP_MEM_HIGH_PRIORITY_TIMER);
-
+#ifdef CONFIG_ARCH_TEGRA_3x_SOC
+ tegra_dc_writel(dc, 0x00000000, DC_DISP_DISP_MISC_CONTROL);
+#endif
/* enable interrupts for vblank, frame_end and underflows */
tegra_dc_writel(dc, (FRAME_END_INT | V_BLANK_INT | ALL_UF_INT),
DC_CMD_INT_ENABLE);
@@ -2534,11 +1245,10 @@ static int tegra_dc_init(struct tegra_dc *dc)
dc->syncpt[i].id = syncpt;
dc->syncpt[i].min = dc->syncpt[i].max =
- nvhost_syncpt_read(&nvhost_get_host(dc->ndev)->syncpt,
- syncpt);
+ nvhost_syncpt_read_ext(dc->ndev, syncpt);
}
- print_mode(dc, &dc->mode, __func__);
+ print_mode_info(dc, dc->mode);
if (dc->mode.pclk)
if (tegra_dc_program_mode(dc, &dc->mode))
@@ -2559,7 +1269,7 @@ static bool _tegra_dc_controller_enable(struct tegra_dc *dc)
dc->out->enable();
tegra_dc_setup_clk(dc, dc->clk);
- clk_enable(dc->clk);
+ tegra_dc_clk_enable(dc);
/* do not accept interrupts during initialization */
tegra_dc_writel(dc, 0, DC_CMD_INT_ENABLE);
@@ -2576,15 +1286,19 @@ static bool _tegra_dc_controller_enable(struct tegra_dc *dc)
if (dc->out_ops && dc->out_ops->enable)
dc->out_ops->enable(dc);
- if (dc->out->postpoweron)
- dc->out->postpoweron();
-
/* force a full blending update */
dc->blend.z[0] = -1;
tegra_dc_ext_enable(dc->ext);
trace_printk("%s:enable\n", dc->ndev->name);
+
+ tegra_dc_writel(dc, GENERAL_UPDATE, DC_CMD_STATE_CONTROL);
+ tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
+
+ if (dc->out->postpoweron)
+ dc->out->postpoweron();
+
return true;
}
@@ -2597,7 +1311,7 @@ static bool _tegra_dc_controller_reset_enable(struct tegra_dc *dc)
dc->out->enable();
tegra_dc_setup_clk(dc, dc->clk);
- clk_enable(dc->clk);
+ tegra_dc_clk_enable(dc);
if (dc->ndev->id == 0 && tegra_dcs[1] != NULL) {
mutex_lock(&tegra_dcs[1]->lock);
@@ -2704,6 +1418,9 @@ static void _tegra_dc_controller_disable(struct tegra_dc *dc)
{
unsigned i;
+ if (dc->out && dc->out->prepoweroff)
+ dc->out->prepoweroff();
+
if (dc->out_ops && dc->out_ops->disable)
dc->out_ops->disable(dc);
@@ -2712,8 +1429,7 @@ static void _tegra_dc_controller_disable(struct tegra_dc *dc)
disable_irq(dc->irq);
tegra_dc_clear_bandwidth(dc);
- clk_disable(dc->clk);
- tegra_dvfs_set_rate(dc->clk, 0);
+ tegra_dc_clk_disable(dc);
if (dc->out && dc->out->disable)
dc->out->disable();
@@ -2733,9 +1449,7 @@ static void _tegra_dc_controller_disable(struct tegra_dc *dc)
trace_printk("%s:syncpt flush id=%d\n", dc->ndev->name,
dc->syncpt[i].id);
dc->syncpt[i].min++;
- nvhost_syncpt_cpu_incr(
- &nvhost_get_host(dc->ndev)->syncpt,
- dc->syncpt[i].id);
+ nvhost_syncpt_cpu_incr_ext(dc->ndev, dc->syncpt[i].id);
}
}
trace_printk("%s:disabled\n", dc->ndev->name);
@@ -2809,6 +1523,9 @@ void tegra_dc_disable(struct tegra_dc *dc)
mutex_lock(&dc->lock);
+ if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_LP_MODE)
+ tegra_dc_host_resume(dc);
+
if (dc->enabled) {
dc->enabled = false;
@@ -2836,7 +1553,8 @@ static void tegra_dc_reset_worker(struct work_struct *work)
mutex_lock(&shared_lock);
- dev_warn(&dc->ndev->dev, "overlay stuck in underflow state. resetting.\n");
+ dev_warn(&dc->ndev->dev,
+ "overlay stuck in underflow state. resetting.\n");
tegra_dc_ext_disable(dc->ext);
@@ -2887,6 +1605,9 @@ static void tegra_dc_underflow_worker(struct work_struct *work)
to_delayed_work(work), struct tegra_dc, underflow_work);
mutex_lock(&dc->lock);
+ if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_LP_MODE)
+ tegra_dc_host_resume(dc);
+
if (dc->enabled) {
tegra_dc_underflow_handler(dc);
}
@@ -2906,9 +1627,11 @@ static ssize_t switch_modeset_print_mode(struct switch_dev *sdev, char *buf)
}
#endif
-static int tegra_dc_probe(struct nvhost_device *ndev)
+static int tegra_dc_probe(struct nvhost_device *ndev,
+ struct nvhost_device_id *id_table)
{
struct tegra_dc *dc;
+ struct tegra_dc_mode *mode;
struct clk *clk;
struct clk *emc_clk;
struct resource *res;
@@ -2944,7 +1667,8 @@ static int tegra_dc_probe(struct nvhost_device *ndev)
goto err_free;
}
- base_res = request_mem_region(res->start, resource_size(res), ndev->name);
+ base_res = request_mem_region(res->start, resource_size(res),
+ ndev->name);
if (!base_res) {
dev_err(&ndev->dev, "request_mem_region failed\n");
ret = -EBUSY;
@@ -3001,6 +1725,7 @@ static int tegra_dc_probe(struct nvhost_device *ndev)
INIT_WORK(&dc->reset_work, tegra_dc_reset_worker);
#endif
INIT_WORK(&dc->vblank_work, tegra_dc_vblank);
+ dc->vblank_ref_count = 0;
INIT_DELAYED_WORK(&dc->underflow_work, tegra_dc_underflow_worker);
INIT_DELAYED_WORK(&dc->one_shot_work, tegra_dc_one_shot_worker);
@@ -3030,6 +1755,8 @@ static int tegra_dc_probe(struct nvhost_device *ndev)
switch_dev_register(&dc->modeset_switch);
#endif
+ tegra_dc_feature_register(dc);
+
if (dc->pdata->default_out)
tegra_dc_set_out(dc, dc->pdata->default_out);
else
@@ -3044,22 +1771,19 @@ static int tegra_dc_probe(struct nvhost_device *ndev)
dc->ext = NULL;
}
+ mutex_lock(&dc->lock);
+ if (dc->pdata->flags & TEGRA_DC_FLAG_ENABLED)
+ dc->enabled = _tegra_dc_enable(dc);
+ mutex_unlock(&dc->lock);
+
/* interrupt handler must be registered before tegra_fb_register() */
- if (request_irq(irq, tegra_dc_irq, IRQF_DISABLED,
+ if (request_irq(irq, tegra_dc_irq, 0,
dev_name(&ndev->dev), dc)) {
dev_err(&ndev->dev, "request_irq %d failed\n", irq);
ret = -EBUSY;
goto err_put_emc_clk;
}
- /* hack to balance enable_irq calls in _tegra_dc_enable() */
- disable_dc_irq(dc->irq);
-
- mutex_lock(&dc->lock);
- if (dc->pdata->flags & TEGRA_DC_FLAG_ENABLED)
- dc->enabled = _tegra_dc_enable(dc);
- mutex_unlock(&dc->lock);
-
tegra_dc_create_debugfs(dc);
dev_info(&ndev->dev, "probed\n");
@@ -3076,6 +1800,12 @@ static int tegra_dc_probe(struct nvhost_device *ndev)
tegra_dc_fmt_bpp(fmt);
}
+ mode = tegra_dc_get_override_mode(dc);
+ if (mode) {
+ dc->pdata->fb->xres = mode->h_active;
+ dc->pdata->fb->yres = mode->v_active;
+ }
+
dc->fb = tegra_fb_register(ndev, dc, dc->pdata->fb, fb_mem);
if (IS_ERR_OR_NULL(dc->fb))
dc->fb = NULL;
@@ -3206,6 +1936,17 @@ static int tegra_dc_resume(struct nvhost_device *ndev)
#endif /* CONFIG_PM */
+static void tegra_dc_shutdown(struct nvhost_device *ndev)
+{
+ struct tegra_dc *dc = nvhost_get_drvdata(ndev);
+
+ if (!dc || !dc->enabled)
+ return;
+
+ tegra_dc_blank(dc);
+ tegra_dc_disable(dc);
+}
+
extern int suspend_set(const char *val, struct kernel_param *kp)
{
if (!strcmp(val, "dump"))
@@ -3240,8 +1981,77 @@ struct nvhost_driver tegra_dc_driver = {
.suspend = tegra_dc_suspend,
.resume = tegra_dc_resume,
#endif
+ .shutdown = tegra_dc_shutdown,
};
+#ifndef MODULE
+static int __init parse_disp_params(char *options, struct tegra_dc_mode *mode)
+{
+ int i, params[11];
+ char *p;
+
+ for (i = 0; i < ARRAY_SIZE(params); i++) {
+ if ((p = strsep(&options, ",")) != NULL) {
+ if (*p)
+ params[i] = simple_strtoul(p, &p, 10);
+ } else
+ return -EINVAL;
+ }
+
+ if ((mode->pclk = params[0]) == 0)
+ return -EINVAL;
+
+ mode->h_active = params[1];
+ mode->v_active = params[2];
+ mode->h_ref_to_sync = params[3];
+ mode->v_ref_to_sync = params[4];
+ mode->h_sync_width = params[5];
+ mode->v_sync_width = params[6];
+ mode->h_back_porch = params[7];
+ mode->v_back_porch = params[8];
+ mode->h_front_porch = params[9];
+ mode->v_front_porch = params[10];
+
+ return 0;
+}
+
+static int __init tegra_dc_mode_override(char *str)
+{
+ char *p = str, *options;
+
+ if (!p || !*p)
+ return -EINVAL;
+
+ p = strstr(str, "hdmi:");
+ if (p) {
+ p += 5;
+ options = strsep(&p, ";");
+ if (parse_disp_params(options, &override_disp_mode[TEGRA_DC_OUT_HDMI]))
+ return -EINVAL;
+ }
+
+ p = strstr(str, "rgb:");
+ if (p) {
+ p += 4;
+ options = strsep(&p, ";");
+ if (parse_disp_params(options, &override_disp_mode[TEGRA_DC_OUT_RGB]))
+ return -EINVAL;
+ }
+
+ p = strstr(str, "dsi:");
+ if (p) {
+ p += 4;
+ options = strsep(&p, ";");
+ if (parse_disp_params(options, &override_disp_mode[TEGRA_DC_OUT_DSI]))
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+__setup("disp_params=", tegra_dc_mode_override);
+#endif
+
static int __init tegra_dc_module_init(void)
{
int ret = tegra_dc_ext_module_init();
diff --git a/drivers/video/tegra/dc/dc_config.c b/drivers/video/tegra/dc/dc_config.c
new file mode 100644
index 000000000000..f238faddab12
--- /dev/null
+++ b/drivers/video/tegra/dc/dc_config.c
@@ -0,0 +1,247 @@
+/*
+ * drivers/video/tegra/dc/dc_config.c
+ *
+ * Copyright (c) 2012, NVIDIA CORPORATION, All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "dc_config.h"
+
+static struct tegra_dc_feature_entry t20_feature_entries_a[] = {
+ { 0, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_A,} },
+ { 0, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+ { 0, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+ { 0, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+ { 0, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 0,} },
+ { 0, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1,} },
+ { 0, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+
+ { 1, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_B,} },
+ { 1, TEGRA_DC_FEATURE_PREFERRED_FORMATS, {TEGRA_WIN_PREF_FMT_WIN_B,} },
+ { 1, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+ { 1, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+ { 1, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+ { 1, TEGRA_DC_FEATURE_FILTER_TYPE, {1, 1,} },
+ { 1, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1,} },
+ { 1, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+
+ { 2, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_C,} },
+ { 2, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+ { 2, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+ { 2, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+ { 2, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 1,} },
+ { 2, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1,} },
+ { 2, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+};
+
+static struct tegra_dc_feature_entry t20_feature_entries_b[] = {
+ { 0, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_A,} },
+ { 0, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+ { 0, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+ { 0, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+ { 0, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 0,} },
+ { 0, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1,} },
+ { 0, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+
+ { 1, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_B,} },
+ { 1, TEGRA_DC_FEATURE_PREFERRED_FORMATS, {TEGRA_WIN_PREF_FMT_WIN_B,} },
+ { 1, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+ { 1, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+ { 1, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+ { 1, TEGRA_DC_FEATURE_FILTER_TYPE, {1, 1,} },
+ { 1, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1,} },
+ { 1, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+
+ { 2, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_C,} },
+ { 2, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+ { 2, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+ { 2, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+ { 2, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 1,} },
+ { 2, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1,} },
+ { 2, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+};
+
+struct tegra_dc_feature t20_feature_table_a = {
+ ARRAY_SIZE(t20_feature_entries_a), t20_feature_entries_a,
+};
+
+struct tegra_dc_feature t20_feature_table_b = {
+ ARRAY_SIZE(t20_feature_entries_b), t20_feature_entries_b,
+};
+
+static struct tegra_dc_feature_entry t30_feature_entries_a[] = {
+ { 0, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_A,} },
+ { 0, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+ { 0, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+ { 0, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+ { 0, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 0,} },
+ { 0, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1} },
+ { 0, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+
+ { 1, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_B,} },
+ { 1, TEGRA_DC_FEATURE_PREFERRED_FORMATS, {TEGRA_WIN_PREF_FMT_WIN_B,} },
+ { 1, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+ { 1, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+ { 1, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+ { 1, TEGRA_DC_FEATURE_FILTER_TYPE, {1, 1,} },
+ { 1, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1} },
+ { 1, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+
+ { 2, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_C,} },
+ { 2, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+ { 2, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+ { 2, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+ { 2, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 1,} },
+ { 2, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1} },
+ { 2, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+};
+
+static struct tegra_dc_feature_entry t30_feature_entries_b[] = {
+ { 0, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_A,} },
+ { 0, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+ { 0, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+ { 0, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+ { 0, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 0,} },
+ { 0, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1,} },
+ { 0, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+
+ { 1, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_B,} },
+ { 1, TEGRA_DC_FEATURE_PREFERRED_FORMATS, {TEGRA_WIN_PREF_FMT_WIN_B,} },
+ { 1, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+ { 1, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+ { 1, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+ { 1, TEGRA_DC_FEATURE_FILTER_TYPE, {1, 1,} },
+ { 1, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1,} },
+ { 1, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+
+ { 2, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_C,} },
+ { 2, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+ { 2, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+ { 2, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+ { 2, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 1,} },
+ { 2, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1,} },
+ { 2, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+};
+
+struct tegra_dc_feature t30_feature_table_a = {
+ ARRAY_SIZE(t30_feature_entries_a), t30_feature_entries_a,
+};
+
+struct tegra_dc_feature t30_feature_table_b = {
+ ARRAY_SIZE(t30_feature_entries_b), t30_feature_entries_b,
+};
+
+int tegra_dc_get_feature(struct tegra_dc_feature *feature, int win_idx,
+ enum tegra_dc_feature_option option)
+{
+ int i;
+ struct tegra_dc_feature_entry *entry;
+
+ if (!feature)
+ return -EINVAL;
+
+ for (i = 0; i < feature->num_entries; i++) {
+ entry = &feature->entries[i];
+ if (entry->window_index == win_idx && entry->option == option)
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+long *tegra_dc_parse_feature(struct tegra_dc *dc, int win_idx, int operation)
+{
+ int idx;
+ struct tegra_dc_feature_entry *entry;
+ enum tegra_dc_feature_option option;
+ struct tegra_dc_feature *feature = dc->feature;
+
+ switch (operation) {
+ case GET_WIN_FORMATS:
+ option = TEGRA_DC_FEATURE_FORMATS;
+ break;
+ case GET_WIN_SIZE:
+ option = TEGRA_DC_FEATURE_MAXIMUM_SIZE;
+ break;
+ case HAS_SCALE:
+ option = TEGRA_DC_FEATURE_MAXIMUM_SCALE;
+ break;
+ case HAS_TILED:
+ option = TEGRA_DC_FEATURE_LAYOUT_TYPE;
+ break;
+ case HAS_V_FILTER:
+ option = TEGRA_DC_FEATURE_FILTER_TYPE;
+ break;
+ case HAS_H_FILTER:
+ option = TEGRA_DC_FEATURE_FILTER_TYPE;
+ break;
+ case HAS_GEN2_BLEND:
+ option = TEGRA_DC_FEATURE_BLEND_TYPE;
+ break;
+ default:
+ return NULL;
+ }
+
+ idx = tegra_dc_get_feature(feature, win_idx, option);
+ if (IS_ERR_VALUE(idx))
+ return NULL;
+ entry = &feature->entries[idx];
+
+ return entry->arg;
+}
+
+int tegra_dc_feature_has_scaling(struct tegra_dc *dc, int win_idx)
+{
+ int i;
+ long *addr = tegra_dc_parse_feature(dc, win_idx, HAS_SCALE);
+
+ for (i = 0; i < ENTRY_SIZE; i++)
+ if (addr[i] != 1)
+ return 1;
+ return 0;
+}
+
+int tegra_dc_feature_has_tiling(struct tegra_dc *dc, int win_idx)
+{
+ long *addr = tegra_dc_parse_feature(dc, win_idx, HAS_TILED);
+
+ return addr[TILED_LAYOUT];
+}
+
+int tegra_dc_feature_has_filter(struct tegra_dc *dc, int win_idx, int operation)
+{
+ long *addr = tegra_dc_parse_feature(dc, win_idx, operation);
+
+ if (operation == HAS_V_FILTER)
+ return addr[V_FILTER];
+ else
+ return addr[H_FILTER];
+}
+
+void tegra_dc_feature_register(struct tegra_dc *dc)
+{
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
+ if (!dc->ndev->id)
+ dc->feature = &t20_feature_table_a;
+ else
+ dc->feature = &t20_feature_table_b;
+#elif defined(CONFIG_ARCH_TEGRA_3x_SOC)
+ if (!dc->ndev->id)
+ dc->feature = &t30_feature_table_a;
+ else
+ dc->feature = &t30_feature_table_b;
+#endif
+}
diff --git a/drivers/video/tegra/dc/dc_config.h b/drivers/video/tegra/dc/dc_config.h
new file mode 100644
index 000000000000..6f5d08ccd82a
--- /dev/null
+++ b/drivers/video/tegra/dc/dc_config.h
@@ -0,0 +1,162 @@
+/*
+ * drivers/video/tegra/dc/dc_config.c
+ * Copyright (c) 2010-2012, NVIDIA CORPORATION, All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 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.
+ */
+
+#ifndef __DRIVERS_VIDEO_TEGRA_DC_DC_CONFIG_H
+#define __DRIVERS_VIDEO_TEGRA_DC_DC_CONFIG_H
+
+#include <linux/errno.h>
+#include <mach/dc.h>
+
+#include "dc_priv.h"
+
+#define ENTRY_SIZE 4 /* Size of feature entry args */
+
+/* Define the supported formats. TEGRA_WIN_FMT_WIN_x macros are defined
+ * based on T20/T30 formats. */
+#define TEGRA_WIN_FMT_BASE_CNT (TEGRA_WIN_FMT_YUV422RA + 1)
+#define TEGRA_WIN_FMT_BASE ((1 << TEGRA_WIN_FMT_P8) | \
+ (1 << TEGRA_WIN_FMT_B4G4R4A4) | \
+ (1 << TEGRA_WIN_FMT_B5G5R5A) | \
+ (1 << TEGRA_WIN_FMT_B5G6R5) | \
+ (1 << TEGRA_WIN_FMT_AB5G5R5) | \
+ (1 << TEGRA_WIN_FMT_B8G8R8A8) | \
+ (1 << TEGRA_WIN_FMT_R8G8B8A8) | \
+ (1 << TEGRA_WIN_FMT_YCbCr422) | \
+ (1 << TEGRA_WIN_FMT_YUV422) | \
+ (1 << TEGRA_WIN_FMT_YCbCr420P) | \
+ (1 << TEGRA_WIN_FMT_YUV420P) | \
+ (1 << TEGRA_WIN_FMT_YCbCr422P) | \
+ (1 << TEGRA_WIN_FMT_YUV422P) | \
+ (1 << TEGRA_WIN_FMT_YCbCr422R) | \
+ (1 << TEGRA_WIN_FMT_YUV422R))
+
+#define TEGRA_WIN_FMT_WIN_A ((1 << TEGRA_WIN_FMT_P1) | \
+ (1 << TEGRA_WIN_FMT_P2) | \
+ (1 << TEGRA_WIN_FMT_P4) | \
+ (1 << TEGRA_WIN_FMT_P8) | \
+ (1 << TEGRA_WIN_FMT_B4G4R4A4) | \
+ (1 << TEGRA_WIN_FMT_B5G5R5A) | \
+ (1 << TEGRA_WIN_FMT_B5G6R5) | \
+ (1 << TEGRA_WIN_FMT_AB5G5R5) | \
+ (1 << TEGRA_WIN_FMT_B8G8R8A8) | \
+ (1 << TEGRA_WIN_FMT_R8G8B8A8) | \
+ (1 << TEGRA_WIN_FMT_B6x2G6x2R6x2A8) | \
+ (1 << TEGRA_WIN_FMT_R6x2G6x2B6x2A8))
+
+#define TEGRA_WIN_FMT_WIN_B (TEGRA_WIN_FMT_BASE | \
+ (1 << TEGRA_WIN_FMT_B6x2G6x2R6x2A8) | \
+ (1 << TEGRA_WIN_FMT_R6x2G6x2B6x2A8) | \
+ (1 << TEGRA_WIN_FMT_YCbCr422RA) | \
+ (1 << TEGRA_WIN_FMT_YUV422RA))
+
+#define TEGRA_WIN_FMT_WIN_C (TEGRA_WIN_FMT_BASE | \
+ (1 << TEGRA_WIN_FMT_B6x2G6x2R6x2A8) | \
+ (1 << TEGRA_WIN_FMT_R6x2G6x2B6x2A8) | \
+ (1 << TEGRA_WIN_FMT_YCbCr422RA) | \
+ (1 << TEGRA_WIN_FMT_YUV422RA))
+
+/* preferred formats do not include 32-bpp formats */
+#define TEGRA_WIN_PREF_FMT_WIN_B (TEGRA_WIN_FMT_WIN_B & \
+ ~(1 << TEGRA_WIN_FMT_B8G8R8A8) & \
+ ~(1 << TEGRA_WIN_FMT_R8G8B8A8))
+
+
+
+/* For each entry, we define the offset to read specific feature. Define the
+ * offset for TEGRA_DC_FEATURE_MAXIMUM_SCALE */
+#define H_SCALE_UP 0
+#define V_SCALE_UP 1
+#define H_FILTER_DOWN 2
+#define V_FILTER_DOWN 3
+
+/* Define the offset for TEGRA_DC_FEATURE_MAXIMUM_SIZE */
+#define MAX_WIDTH 0
+#define MIN_WIDTH 1
+#define MAX_HEIGHT 2
+#define MIN_HEIGHT 3
+#define CHECK_SIZE(val, min, max) ( \
+ ((val) < (min) || (val) > (max)) ? -EINVAL : 0)
+
+/* Define the offset for TEGRA_DC_FEATURE_FILTER_TYPE */
+#define V_FILTER 0
+#define H_FILTER 1
+
+/* Define the offset for TEGRA_DC_FEATURE_INVERT_TYPE */
+#define H_INVERT 0
+#define V_INVERT 1
+#define SCAN_COLUMN 2
+
+/* Define the offset for TEGRA_DC_FEATURE_LAYOUT_TYPE. */
+#define PITCHED_LAYOUT 0
+#define TILED_LAYOUT 1
+
+/* Available operations on feature table. */
+enum {
+ HAS_SCALE,
+ HAS_TILED,
+ HAS_V_FILTER,
+ HAS_H_FILTER,
+ HAS_GEN2_BLEND,
+ GET_WIN_FORMATS,
+ GET_WIN_SIZE,
+};
+
+enum tegra_dc_feature_option {
+ TEGRA_DC_FEATURE_FORMATS,
+ TEGRA_DC_FEATURE_BLEND_TYPE,
+ TEGRA_DC_FEATURE_MAXIMUM_SIZE,
+ TEGRA_DC_FEATURE_MAXIMUM_SCALE,
+ TEGRA_DC_FEATURE_FILTER_TYPE,
+ TEGRA_DC_FEATURE_LAYOUT_TYPE,
+ TEGRA_DC_FEATURE_INVERT_TYPE,
+ TEGRA_DC_FEATURE_PREFERRED_FORMATS,
+};
+
+struct tegra_dc_feature_entry {
+ u32 window_index;
+ u32 option;
+ long arg[ENTRY_SIZE];
+};
+
+struct tegra_dc_feature {
+ u32 num_entries;
+ struct tegra_dc_feature_entry *entries;
+};
+
+int tegra_dc_feature_has_scaling(struct tegra_dc *dc, int win_idx);
+int tegra_dc_feature_has_tiling(struct tegra_dc *dc, int win_idx);
+int tegra_dc_feature_has_filter(struct tegra_dc *dc, int win_idx, int operation);
+
+long *tegra_dc_parse_feature(struct tegra_dc *dc, int win_idx, int operation);
+void tegra_dc_feature_register(struct tegra_dc *dc);
+
+static inline bool win_use_v_filter(struct tegra_dc *dc,
+ const struct tegra_dc_win *win)
+{
+ return tegra_dc_feature_has_filter(dc, win->idx, HAS_V_FILTER) &&
+ win->h.full != dfixed_const(win->out_h);
+}
+static inline bool win_use_h_filter(struct tegra_dc *dc,
+ const struct tegra_dc_win *win)
+{
+ return tegra_dc_feature_has_filter(dc, win->idx, HAS_H_FILTER) &&
+ win->w.full != dfixed_const(win->out_w);
+}
+
+#endif
diff --git a/drivers/video/tegra/dc/dc_priv.h b/drivers/video/tegra/dc/dc_priv.h
index d16279a4c63d..fb1243593587 100644
--- a/drivers/video/tegra/dc/dc_priv.h
+++ b/drivers/video/tegra/dc/dc_priv.h
@@ -4,6 +4,8 @@
* Copyright (C) 2010 Google, Inc.
* Author: Erik Gilling <konkers@android.com>
*
+ * Copyright (c) 2010-2012, NVIDIA CORPORATION, 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.
@@ -22,15 +24,17 @@
#include <linux/mutex.h>
#include <linux/wait.h>
#include <linux/fb.h>
+#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/switch.h>
+#include <linux/nvhost.h>
#include <mach/dc.h>
-#include "../host/dev.h"
-#include "../host/host1x/host1x_syncpt.h"
-
#include <mach/tegra_dc_ext.h>
+#include <mach/clk.h>
+
+#include "dc_reg.h"
#define WIN_IS_TILED(win) ((win)->flags & TEGRA_WIN_FLAG_TILED)
#define WIN_IS_ENABLED(win) ((win)->flags & TEGRA_WIN_FLAG_ENABLED)
@@ -46,6 +50,13 @@
#define EMC_BW_TO_FREQ(bw) (DDR_BW_TO_FREQ(bw) * 2)
#endif
+#ifndef CONFIG_TEGRA_FPGA_PLATFORM
+#define ALL_UF_INT (WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT)
+#else
+/* ignore underflows when on simulation and fpga platform */
+#define ALL_UF_INT (0)
+#endif
+
struct tegra_dc;
struct tegra_dc_blend {
@@ -69,7 +80,7 @@ struct tegra_dc_out_ops {
/* resume output. dc clocks are on at this point */
void (*resume)(struct tegra_dc *dc);
/* mode filter. to provide a list of supported modes*/
- bool (*mode_filter)(struct tegra_dc *dc,
+ bool (*mode_filter)(const struct tegra_dc *dc,
struct fb_videomode *mode);
};
@@ -126,6 +137,7 @@ struct tegra_dc {
struct completion frame_end_complete;
struct work_struct vblank_work;
+ long vblank_ref_count;
struct {
u64 underflows;
@@ -136,6 +148,8 @@ struct tegra_dc {
struct tegra_dc_ext *ext;
+ struct tegra_dc_feature *feature;
+
#ifdef CONFIG_DEBUG_FS
struct dentry *debugdir;
#endif
@@ -145,14 +159,31 @@ struct tegra_dc {
struct delayed_work one_shot_work;
};
+#define print_mode_info(dc, mode) do { \
+ trace_printk("%s:Mode settings: " \
+ "ref_to_sync: H = %d V = %d, " \
+ "sync_width: H = %d V = %d, " \
+ "back_porch: H = %d V = %d, " \
+ "active: H = %d V = %d, " \
+ "front_porch: H = %d V = %d, " \
+ "pclk = %d, stereo mode = %d\n", \
+ dc->ndev->name, \
+ mode.h_ref_to_sync, mode.v_ref_to_sync, \
+ mode.h_sync_width, mode.v_sync_width, \
+ mode.h_back_porch, mode.v_back_porch, \
+ mode.h_active, mode.v_active, \
+ mode.h_front_porch, mode.v_front_porch, \
+ mode.pclk, mode.stereo_mode); \
+ } while (0)
+
static inline void tegra_dc_io_start(struct tegra_dc *dc)
{
- nvhost_module_busy(nvhost_get_host(dc->ndev)->dev);
+ nvhost_module_busy_ext(nvhost_get_parent(dc->ndev));
}
static inline void tegra_dc_io_end(struct tegra_dc *dc)
{
- nvhost_module_idle(nvhost_get_host(dc->ndev)->dev);
+ nvhost_module_idle_ext(nvhost_get_parent(dc->ndev));
}
static inline unsigned long tegra_dc_readl(struct tegra_dc *dc,
@@ -160,7 +191,10 @@ static inline unsigned long tegra_dc_readl(struct tegra_dc *dc,
{
unsigned long ret;
- BUG_ON(!nvhost_module_powered(nvhost_get_host(dc->ndev)->dev));
+ BUG_ON(!nvhost_module_powered_ext(nvhost_get_parent(dc->ndev)));
+ if (!tegra_is_clk_enabled(dc->clk))
+ WARN(1, "DC is clock-gated.\n");
+
ret = readl(dc->base + reg * 4);
trace_printk("readl %p=%#08lx\n", dc->base + reg * 4, ret);
return ret;
@@ -169,7 +203,10 @@ static inline unsigned long tegra_dc_readl(struct tegra_dc *dc,
static inline void tegra_dc_writel(struct tegra_dc *dc, unsigned long val,
unsigned long reg)
{
- BUG_ON(!nvhost_module_powered(nvhost_get_host(dc->ndev)->dev));
+ BUG_ON(!nvhost_module_powered_ext(nvhost_get_parent(dc->ndev)));
+ if (!tegra_is_clk_enabled(dc->clk))
+ WARN(1, "DC is clock-gated.\n");
+
trace_printk("writel %p=%#08lx\n", dc->base + reg * 4, val);
writel(val, dc->base + reg * 4);
}
@@ -197,12 +234,117 @@ static inline void *tegra_dc_get_outdata(struct tegra_dc *dc)
}
static inline unsigned long tegra_dc_get_default_emc_clk_rate(
- struct tegra_dc *dc)
+ struct tegra_dc *dc)
{
return dc->pdata->emc_clk_rate ? dc->pdata->emc_clk_rate : ULONG_MAX;
}
-void tegra_dc_setup_clk(struct tegra_dc *dc, struct clk *clk);
+static inline int tegra_dc_fmt_bpp(int fmt)
+{
+ switch (fmt) {
+ case TEGRA_WIN_FMT_P1:
+ return 1;
+
+ case TEGRA_WIN_FMT_P2:
+ return 2;
+
+ case TEGRA_WIN_FMT_P4:
+ return 4;
+
+ case TEGRA_WIN_FMT_P8:
+ return 8;
+
+ case TEGRA_WIN_FMT_B4G4R4A4:
+ case TEGRA_WIN_FMT_B5G5R5A:
+ case TEGRA_WIN_FMT_B5G6R5:
+ case TEGRA_WIN_FMT_AB5G5R5:
+ return 16;
+
+ case TEGRA_WIN_FMT_B8G8R8A8:
+ case TEGRA_WIN_FMT_R8G8B8A8:
+ case TEGRA_WIN_FMT_B6x2G6x2R6x2A8:
+ case TEGRA_WIN_FMT_R6x2G6x2B6x2A8:
+ return 32;
+
+ /* for planar formats, size of the Y plane, 8bit */
+ case TEGRA_WIN_FMT_YCbCr420P:
+ case TEGRA_WIN_FMT_YUV420P:
+ case TEGRA_WIN_FMT_YCbCr422P:
+ case TEGRA_WIN_FMT_YUV422P:
+ case TEGRA_WIN_FMT_YCbCr422R:
+ case TEGRA_WIN_FMT_YUV422R:
+ case TEGRA_WIN_FMT_YCbCr422RA:
+ case TEGRA_WIN_FMT_YUV422RA:
+ return 8;
+
+ /* YUYV packed into 32-bits */
+ case TEGRA_WIN_FMT_YCbCr422:
+ case TEGRA_WIN_FMT_YUV422:
+ return 16;
+ }
+ return 0;
+}
+
+static inline bool tegra_dc_is_yuv(int fmt)
+{
+ switch (fmt) {
+ case TEGRA_WIN_FMT_YUV420P:
+ case TEGRA_WIN_FMT_YCbCr420P:
+ case TEGRA_WIN_FMT_YCbCr422P:
+ case TEGRA_WIN_FMT_YUV422P:
+ case TEGRA_WIN_FMT_YCbCr422:
+ case TEGRA_WIN_FMT_YUV422:
+ case TEGRA_WIN_FMT_YCbCr422R:
+ case TEGRA_WIN_FMT_YUV422R:
+ case TEGRA_WIN_FMT_YCbCr422RA:
+ case TEGRA_WIN_FMT_YUV422RA:
+ return true;
+ }
+ return false;
+}
+
+static inline bool tegra_dc_is_yuv_planar(int fmt)
+{
+ switch (fmt) {
+ case TEGRA_WIN_FMT_YUV420P:
+ case TEGRA_WIN_FMT_YCbCr420P:
+ case TEGRA_WIN_FMT_YCbCr422P:
+ case TEGRA_WIN_FMT_YUV422P:
+ case TEGRA_WIN_FMT_YCbCr422R:
+ case TEGRA_WIN_FMT_YUV422R:
+ case TEGRA_WIN_FMT_YCbCr422RA:
+ case TEGRA_WIN_FMT_YUV422RA:
+ return true;
+ }
+ return false;
+}
+
+static inline void tegra_dc_unmask_interrupt(struct tegra_dc *dc, u32 int_val)
+{
+ u32 val;
+
+ val = tegra_dc_readl(dc, DC_CMD_INT_MASK);
+ val |= int_val;
+ tegra_dc_writel(dc, val, DC_CMD_INT_MASK);
+}
+
+static inline void tegra_dc_mask_interrupt(struct tegra_dc *dc, u32 int_val)
+{
+ u32 val;
+
+ val = tegra_dc_readl(dc, DC_CMD_INT_MASK);
+ val &= ~int_val;
+ tegra_dc_writel(dc, val, DC_CMD_INT_MASK);
+}
+
+static inline unsigned long tegra_dc_clk_get_rate(struct tegra_dc *dc)
+{
+#ifdef CONFIG_TEGRA_SILICON_PLATFORM
+ return clk_get_rate(dc->clk);
+#else
+ return dc->mode.pclk;
+#endif
+}
extern struct tegra_dc_out_ops tegra_dc_rgb_ops;
extern struct tegra_dc_out_ops tegra_dc_hdmi_ops;
@@ -224,5 +366,31 @@ void tegra_dc_disable_crc(struct tegra_dc *dc);
void tegra_dc_set_out_pin_polars(struct tegra_dc *dc,
const struct tegra_dc_out_pin *pins,
const unsigned int n_pins);
-#endif
+/* defined in dc.c, used in bandwidth.c */
+unsigned int tegra_dc_has_multiple_dc(void);
+
+/* defined in bandwidth.c, used in dc.c */
+void tegra_dc_clear_bandwidth(struct tegra_dc *dc);
+void tegra_dc_program_bandwidth(struct tegra_dc *dc, bool use_new);
+int tegra_dc_set_dynamic_emc(struct tegra_dc_win *windows[], int n);
+
+/* defined in mode.c, used in dc.c */
+int tegra_dc_program_mode(struct tegra_dc *dc, struct tegra_dc_mode *mode);
+int tegra_dc_calc_refresh(const struct tegra_dc_mode *m);
+
+/* defined in clock.c, used in dc.c, dsi.c and hdmi.c */
+void tegra_dc_setup_clk(struct tegra_dc *dc, struct clk *clk);
+unsigned long tegra_dc_pclk_round_rate(struct tegra_dc *dc, int pclk);
+
+/* defined in lut.c, used in dc.c */
+void tegra_dc_init_lut_defaults(struct tegra_dc_lut *lut);
+void tegra_dc_set_lut(struct tegra_dc *dc, struct tegra_dc_win *win);
+
+/* defined in csc.c, used in dc.c */
+void tegra_dc_init_csc_defaults(struct tegra_dc_csc *csc);
+void tegra_dc_set_csc(struct tegra_dc *dc, struct tegra_dc_csc *csc);
+/* defined in window.c, used in dc.c */
+void tegra_dc_trigger_windows(struct tegra_dc *dc);
+
+#endif
diff --git a/drivers/video/tegra/dc/dc_reg.h b/drivers/video/tegra/dc/dc_reg.h
index 22379a194082..86b1029d3bba 100644
--- a/drivers/video/tegra/dc/dc_reg.h
+++ b/drivers/video/tegra/dc/dc_reg.h
@@ -4,7 +4,7 @@
* Copyright (C) 2010 Google, Inc.
* Author: Erik Gilling <konkers@android.com>
*
- * Copyright (C) 2010-2011 NVIDIA Corporation
+ * Copyright (c) 2010-2012, NVIDIA CORPORATION, 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
@@ -367,6 +367,7 @@
#define DC_DISP_MCCIF_DISPLAY1B_HYST 0x484
#define DC_DISP_DAC_CRT_CTRL 0x4c0
#define DC_DISP_DISP_MISC_CONTROL 0x4c1
+#define UF_LINE_FLUSH (1 << 1)
#define DC_WIN_COLOR_PALETTE(x) (0x500 + (x))
@@ -430,6 +431,8 @@
#define DC_WIN_LINE_STRIDE 0x70a
#define LINE_STRIDE(x) (x)
#define UV_LINE_STRIDE(x) (((x) & 0xffff) << 16)
+#define GET_LINE_STRIDE(x) ((x) & 0xffff)
+#define GET_UV_LINE_STRIDE(x) (((x) >> 16) & 0xffff)
#define DC_WIN_BUF_STRIDE 0x70b
#define DC_WIN_UV_BUF_STRIDE 0x70c
#define DC_WIN_BUFFER_ADDR_MODE 0x70d
@@ -459,6 +462,12 @@
#define DC_WIN_HP_FETCH_CONTROL 0x714
+
+#ifdef CONFIG_ARCH_TEGRA_3x_SOC
+#define DC_WIN_GLOBAL_ALPHA 0x715
+#define GLOBAL_ALPHA_ENABLE 0x10000
+#endif
+
#define DC_WINBUF_START_ADDR 0x800
#define DC_WINBUF_START_ADDR_NS 0x801
#define DC_WINBUF_START_ADDR_U 0x802
diff --git a/drivers/video/tegra/dc/dc_sysfs.c b/drivers/video/tegra/dc/dc_sysfs.c
index 0b259c374360..bf27e963f233 100644
--- a/drivers/video/tegra/dc/dc_sysfs.c
+++ b/drivers/video/tegra/dc/dc_sysfs.c
@@ -1,7 +1,7 @@
/*
* drivers/video/tegra/dc/dc_sysfs.c
*
- * Copyright (c) 2011, NVIDIA Corporation.
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION, All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/video/tegra/dc/dsi.c b/drivers/video/tegra/dc/dsi.c
index 4b055ec529c6..7ee9375f58f1 100644
--- a/drivers/video/tegra/dc/dsi.c
+++ b/drivers/video/tegra/dc/dsi.c
@@ -1,7 +1,7 @@
/*
* drivers/video/tegra/dc/dsi.c
*
- * Copyright (c) 2011, NVIDIA Corporation.
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION, 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
@@ -14,23 +14,25 @@
*
*/
+#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/fb.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
-#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
+#include <linux/nvhost.h>
#include <mach/clk.h>
#include <mach/dc.h>
#include <mach/fb.h>
#include <mach/csi.h>
+#include <mach/iomap.h>
#include <linux/nvhost.h>
#include "dc_reg.h"
@@ -38,6 +40,9 @@
#include "dsi_regs.h"
#include "dsi.h"
+#define APB_MISC_GP_MIPI_PAD_CTRL_0 (TEGRA_APB_MISC_BASE + 0x820)
+#define DSIB_MODE_ENABLE 0x2
+
#define DSI_USE_SYNC_POINTS 1
#define S_TO_MS(x) (1000 * (x))
@@ -109,6 +114,7 @@ struct tegra_dc_dsi_data {
struct clk *dc_clk;
struct clk *dsi_clk;
+ struct clk *dsi_fixed_clk;
bool clk_ref;
struct mutex lock;
@@ -120,6 +126,10 @@ struct tegra_dc_dsi_data {
struct dsi_phy_timing_inclk phy_timing;
+ bool ulpm;
+ bool enabled;
+ bool host_suspended;
+
u8 driven_mode;
u8 controller_index;
@@ -141,9 +151,6 @@ struct tegra_dc_dsi_data {
u32 current_dsi_clk_khz;
u32 dsi_control_val;
-
- bool ulpm;
- bool enabled;
};
const u32 dsi_pkt_seq_reg[NUMOF_PKT_SEQ] = {
@@ -291,7 +298,7 @@ inline unsigned long tegra_dsi_readl(struct tegra_dc_dsi_data *dsi, u32 reg)
{
unsigned long ret;
- BUG_ON(!nvhost_module_powered(nvhost_get_host(dsi->dc->ndev)->dev));
+ BUG_ON(!nvhost_module_powered_ext(nvhost_get_parent(dsi->dc->ndev)));
ret = readl(dsi->base + reg * 4);
trace_printk("readl %p=%#08lx\n", dsi->base + reg * 4, ret);
return ret;
@@ -300,7 +307,7 @@ EXPORT_SYMBOL(tegra_dsi_readl);
inline void tegra_dsi_writel(struct tegra_dc_dsi_data *dsi, u32 val, u32 reg)
{
- BUG_ON(!nvhost_module_powered(nvhost_get_host(dsi->dc->ndev)->dev));
+ BUG_ON(!nvhost_module_powered_ext(nvhost_get_parent(dsi->dc->ndev)));
trace_printk("writel %p=%#08x\n", dsi->base + reg * 4, val);
writel(val, dsi->base + reg * 4);
}
@@ -411,6 +418,22 @@ static inline void tegra_dc_dsi_debug_create(struct tegra_dc_dsi_data *dsi)
{ }
#endif
+static inline void tegra_dsi_clk_enable(struct tegra_dc_dsi_data *dsi)
+{
+ if (!tegra_is_clk_enabled(dsi->dsi_clk)) {
+ clk_enable(dsi->dsi_clk);
+ clk_enable(dsi->dsi_fixed_clk);
+ }
+}
+
+static inline void tegra_dsi_clk_disable(struct tegra_dc_dsi_data *dsi)
+{
+ if (tegra_is_clk_enabled(dsi->dsi_clk)) {
+ clk_disable(dsi->dsi_clk);
+ clk_disable(dsi->dsi_fixed_clk);
+ }
+}
+
static int tegra_dsi_syncpt(struct tegra_dc_dsi_data *dsi)
{
u32 val;
@@ -418,17 +441,15 @@ static int tegra_dsi_syncpt(struct tegra_dc_dsi_data *dsi)
ret = 0;
- dsi->syncpt_val = nvhost_syncpt_read(
- &nvhost_get_host(dsi->dc->ndev)->syncpt,
- dsi->syncpt_id);
+ dsi->syncpt_val = nvhost_syncpt_read_ext(dsi->dc->ndev, dsi->syncpt_id);
val = DSI_INCR_SYNCPT_COND(OP_DONE) |
DSI_INCR_SYNCPT_INDX(dsi->syncpt_id);
tegra_dsi_writel(dsi, val, DSI_INCR_SYNCPT);
/* TODO: Use interrupt rather than polling */
- ret = nvhost_syncpt_wait(&nvhost_get_host(dsi->dc->ndev)->syncpt,
- dsi->syncpt_id, dsi->syncpt_val + 1);
+ ret = nvhost_syncpt_wait_timeout_ext(dsi->dc->ndev, dsi->syncpt_id,
+ dsi->syncpt_val + 1, MAX_SCHEDULE_TIMEOUT, NULL);
if (ret < 0) {
dev_err(&dsi->dc->ndev->dev, "DSI sync point failure\n");
goto fail;
@@ -1052,7 +1073,7 @@ static u32 tegra_dsi_sol_delay_burst(struct tegra_dc *dc,
u32 dsi_to_pixel_clk_ratio;
u32 temp;
u32 temp1;
- u32 mipi_clk_adj_kHz;
+ u32 mipi_clk_adj_kHz = 0;
u32 sol_delay;
struct tegra_dc_mode *dc_modes = &dc->mode;
@@ -1450,11 +1471,9 @@ static void tegra_dsi_set_dsi_clk(struct tegra_dc *dc,
/* Enable DSI clock */
tegra_dc_setup_clk(dc, dsi->dsi_clk);
- if (!dsi->clk_ref) {
- dsi->clk_ref = true;
- clk_enable(dsi->dsi_clk);
- tegra_periph_reset_deassert(dsi->dsi_clk);
- }
+ tegra_dsi_clk_enable(dsi);
+ tegra_periph_reset_deassert(dsi->dsi_clk);
+
dsi->current_dsi_clk_khz = clk_get_rate(dsi->dsi_clk) / 1000;
dsi->current_bit_clk_ns = 1000*1000 / (dsi->current_dsi_clk_khz * 2);
}
@@ -1619,6 +1638,15 @@ static void tegra_dsi_pad_calibration(struct tegra_dc_dsi_data *dsi)
tegra_vi_csi_writel(val, CSI_CIL_PAD_CONFIG);
}
+static void tegra_dsi_panelB_enable(void)
+{
+ unsigned int val;
+
+ val = readl(IO_ADDRESS(APB_MISC_GP_MIPI_PAD_CTRL_0));
+ val |= DSIB_MODE_ENABLE;
+ writel(val, (IO_ADDRESS(APB_MISC_GP_MIPI_PAD_CTRL_0)));
+}
+
static int tegra_dsi_init_hw(struct tegra_dc *dc,
struct tegra_dc_dsi_data *dsi)
{
@@ -1632,7 +1660,7 @@ static int tegra_dsi_init_hw(struct tegra_dc *dc,
tegra_dsi_set_dsi_clk(dc, dsi, dsi->target_lp_clk_khz);
if (dsi->info.dsi_instance) {
- /* TODO:Set the misc register*/
+ tegra_dsi_panelB_enable();
}
/* TODO: only need to change the timing for bta */
@@ -1929,6 +1957,10 @@ static struct dsi_status *tegra_dsi_prepare_host_transmission(
if (tegra_dsi_host_busy(dsi)) {
tegra_dsi_soft_reset(dsi);
+
+ /* WAR to stop host write in middle */
+ tegra_dsi_writel(dsi, TEGRA_DSI_DISABLE, DSI_TRIGGER);
+
if (tegra_dsi_host_busy(dsi)) {
err = -EBUSY;
dev_err(&dc->ndev->dev, "DSI host busy\n");
@@ -2174,6 +2206,9 @@ int tegra_dsi_send_panel_short_cmd(struct tegra_dc *dc, u8 *pdata, u8 data_len)
int err = 0, count = 0;
struct tegra_dc_dsi_data *dsi = tegra_dc_get_outdata(dc);
+ if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_LP_MODE)
+ tegra_dc_host_resume(dc);
+
data_len_orig = data_len;
if (pdata != NULL) {
while (data_len) {
@@ -2240,9 +2275,7 @@ static int tegra_dsi_bta(struct tegra_dc_dsi_data *dsi)
tegra_dsi_writel(dsi, val, DSI_HOST_DSI_CONTROL);
#if DSI_USE_SYNC_POINTS
- /* FIXME: Workaround for nvhost_syncpt_read */
- dsi->syncpt_val = nvhost_syncpt_update_min(
- &nvhost_get_host(dsi->dc->ndev)->syncpt,
+ dsi->syncpt_val = nvhost_syncpt_read_ext(dsi->dc->ndev,
dsi->syncpt_id);
val = DSI_INCR_SYNCPT_COND(OP_DONE) |
@@ -2250,8 +2283,8 @@ static int tegra_dsi_bta(struct tegra_dc_dsi_data *dsi)
tegra_dsi_writel(dsi, val, DSI_INCR_SYNCPT);
/* TODO: Use interrupt rather than polling */
- err = nvhost_syncpt_wait(&nvhost_get_host(dsi->dc->ndev)->syncpt,
- dsi->syncpt_id, dsi->syncpt_val + 1);
+ err = nvhost_syncpt_wait_timeout_ext(dsi->dc->ndev, dsi->syncpt_id,
+ dsi->syncpt_val + 1, MAX_SCHEDULE_TIMEOUT, NULL);
if (err < 0)
dev_err(&dsi->dc->ndev->dev,
"DSI sync point failure\n");
@@ -2582,6 +2615,53 @@ fail:
}
+static void tegra_dsi_send_dc_frames(struct tegra_dc *dc,
+ struct tegra_dc_dsi_data *dsi,
+ int no_of_frames)
+{
+ int err;
+ u32 frame_period = DIV_ROUND_UP(S_TO_MS(1), dsi->info.refresh_rate);
+ u8 lp_op = dsi->status.lp_op;
+ bool switch_to_lp = (dsi->status.lphs == DSI_LPHS_IN_LP_MODE);
+
+ if (dsi->status.lphs != DSI_LPHS_IN_HS_MODE) {
+ err = tegra_dsi_set_to_hs_mode(dc, dsi);
+ if (err < 0) {
+ dev_err(&dc->ndev->dev,
+ "Switch to HS host mode failed\n");
+ return;
+ }
+ }
+
+ /*
+ * Some panels need DC frames be sent under certain
+ * conditions. We are working on the right fix for this
+ * requirement, while using this current fix.
+ */
+ tegra_dsi_start_dc_stream(dc, dsi);
+
+ /*
+ * Send frames in Continuous or One-shot mode.
+ */
+ if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) {
+ while (no_of_frames--) {
+ tegra_dc_writel(dc, GENERAL_ACT_REQ | NC_HOST_TRIG,
+ DC_CMD_STATE_CONTROL);
+ mdelay(frame_period);
+ }
+ } else
+ mdelay(no_of_frames * frame_period);
+
+ tegra_dsi_stop_dc_stream_at_frame_end(dc, dsi);
+
+ if (switch_to_lp) {
+ err = tegra_dsi_set_to_lp_mode(dc, dsi, lp_op);
+ if (err < 0)
+ dev_err(&dc->ndev->dev,
+ "DSI failed to go to LP mode\n");
+ }
+}
+
static void tegra_dc_dsi_enable(struct tegra_dc *dc)
{
struct tegra_dc_dsi_data *dsi = tegra_dc_get_outdata(dc);
@@ -2591,6 +2671,8 @@ static void tegra_dc_dsi_enable(struct tegra_dc *dc)
tegra_dc_io_start(dc);
mutex_lock(&dsi->lock);
+ if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_LP_MODE)
+ tegra_dc_host_resume(dc);
/* Stop DC stream before configuring DSI registers
* to avoid visible glitches on panel during transition
* from bootloader to kernel driver
@@ -2607,6 +2689,13 @@ static void tegra_dc_dsi_enable(struct tegra_dc *dc)
}
if (dsi->info.panel_reset) {
+ /*
+ * Certain panels need dc frames be sent before
+ * waking panel.
+ */
+ if (dsi->info.panel_send_dc_frames)
+ tegra_dsi_send_dc_frames(dc, dsi, 2);
+
err = tegra_dsi_send_panel_cmd(dc, dsi,
dsi->info.dsi_init_cmd,
dsi->info.n_init_cmd);
@@ -2660,6 +2749,13 @@ static void tegra_dc_dsi_enable(struct tegra_dc *dc)
}
}
+ /*
+ * Certain panels need dc frames be sent before
+ * waking panel.
+ */
+ if (dsi->info.panel_send_dc_frames)
+ tegra_dsi_send_dc_frames(dc, dsi, 2);
+
err = tegra_dsi_set_to_lp_mode(dc, dsi, DSI_LP_OP_WRITE);
if (err < 0) {
dev_err(&dc->ndev->dev,
@@ -2732,8 +2828,8 @@ static int tegra_dc_dsi_cp_info(struct tegra_dc_dsi_data *dsi,
struct tegra_dsi_out *p_dsi)
{
struct tegra_dsi_cmd *p_init_cmd;
- struct tegra_dsi_cmd *p_early_suspend_cmd;
- struct tegra_dsi_cmd *p_late_resume_cmd;
+ struct tegra_dsi_cmd *p_early_suspend_cmd = NULL;
+ struct tegra_dsi_cmd *p_late_resume_cmd = NULL;
struct tegra_dsi_cmd *p_suspend_cmd;
int err;
@@ -2861,6 +2957,7 @@ static int tegra_dc_dsi_init(struct tegra_dc *dc)
void __iomem *base;
struct clk *dc_clk = NULL;
struct clk *dsi_clk = NULL;
+ struct clk *dsi_fixed_clk = NULL;
struct tegra_dsi_out *dsi_pdata;
int err;
@@ -2903,8 +3000,9 @@ static int tegra_dc_dsi_init(struct tegra_dc *dc)
dsi_clk = clk_get(&dc->ndev->dev, "dsib");
else
dsi_clk = clk_get(&dc->ndev->dev, "dsia");
+ dsi_fixed_clk = clk_get(&dc->ndev->dev, "dsi-fixed");
- if (IS_ERR_OR_NULL(dsi_clk)) {
+ if (IS_ERR_OR_NULL(dsi_clk) || IS_ERR_OR_NULL(dsi_fixed_clk)) {
dev_err(&dc->ndev->dev, "dsi: can't get clock\n");
err = -EBUSY;
goto err_release_regs;
@@ -2924,6 +3022,7 @@ static int tegra_dc_dsi_init(struct tegra_dc *dc)
dsi->base_res = base_res;
dsi->dc_clk = dc_clk;
dsi->dsi_clk = dsi_clk;
+ dsi->dsi_fixed_clk = dsi_fixed_clk;
err = tegra_dc_dsi_cp_info(dsi, dsi_pdata);
if (err < 0)
@@ -2937,6 +3036,7 @@ static int tegra_dc_dsi_init(struct tegra_dc *dc)
err_dsi_data:
err_clk_put:
clk_put(dsi_clk);
+ clk_put(dsi_fixed_clk);
err_release_regs:
release_resource(base_res);
err_free_dsi:
@@ -2983,78 +3083,180 @@ static void tegra_dc_dsi_destroy(struct tegra_dc *dc)
kfree(dsi);
}
-static int tegra_dsi_deep_sleep(struct tegra_dc *dc,
- struct tegra_dc_dsi_data *dsi)
+static void tegra_dsi_config_phy_clk(struct tegra_dc_dsi_data *dsi,
+ u32 settings)
{
- int err = 0;
- int val;
struct clk *parent_clk = NULL;
struct clk *base_clk = NULL;
+ /* Disable dsi fast and slow clock */
+ parent_clk = clk_get_parent(dsi->dsi_clk);
+ base_clk = clk_get_parent(parent_clk);
+ if (dsi->info.dsi_instance)
+ tegra_clk_cfg_ex(base_clk,
+ TEGRA_CLK_PLLD_CSI_OUT_ENB,
+ settings);
+ else
+ tegra_clk_cfg_ex(base_clk,
+ TEGRA_CLK_PLLD_DSI_OUT_ENB,
+ settings);
+}
+
+static int tegra_dsi_deep_sleep(struct tegra_dc *dc,
+ struct tegra_dc_dsi_data *dsi, u32 suspend_aggr)
+{
+ int val = 0;
+ int err = 0;
+
if (!dsi->enabled) {
err = -EPERM;
goto fail;
}
- err = tegra_dsi_set_to_lp_mode(dc, dsi, DSI_LP_OP_WRITE);
- if (err < 0) {
- dev_err(&dc->ndev->dev,
- "DSI failed to go to LP mode\n");
- goto fail;
- }
+ switch (suspend_aggr) {
+ case DSI_SUSPEND_FULL:
+ /* Suspend DSI panel */
+ err = tegra_dsi_set_to_lp_mode(dc, dsi, DSI_LP_OP_WRITE);
+ if (err < 0) {
+ dev_err(&dc->ndev->dev,
+ "DSI failed to go to LP mode\n");
+ goto fail;
+ }
- /* Suspend panel */
- err = tegra_dsi_send_panel_cmd(dc, dsi,
- dsi->info.dsi_suspend_cmd,
- dsi->info.n_suspend_cmd);
- if (err < 0) {
- dev_err(&dc->ndev->dev,
- "dsi: Error sending suspend cmd\n");
- goto fail;
- }
+ err = tegra_dsi_send_panel_cmd(dc, dsi,
+ dsi->info.dsi_suspend_cmd,
+ dsi->info.n_suspend_cmd);
+ /*
+ * Certain panels need dc frames be sent after
+ * putting panel to sleep.
+ */
+ if (dsi->info.panel_send_dc_frames)
+ tegra_dsi_send_dc_frames(dc, dsi, 2);
- if (!dsi->ulpm) {
- err = tegra_dsi_enter_ulpm(dsi);
if (err < 0) {
dev_err(&dc->ndev->dev,
- "DSI failed to enter ulpm\n");
+ "dsi: Error sending suspend cmd\n");
goto fail;
}
+ case DSI_HOST_SUSPEND_LV2:
+ /* Set DSI to ULPM and suspend pads. DSI will be set to the
+ * lowest power state in this level. */
+ if (!dsi->ulpm) {
+ err = tegra_dsi_enter_ulpm(dsi);
+ if (err < 0) {
+ dev_err(&dc->ndev->dev,
+ "DSI failed to enter ulpm\n");
+ goto fail;
+ }
+ }
+
+ val = DSI_PAD_CONTROL_PAD_PDIO(0x3) |
+ DSI_PAD_CONTROL_PAD_PDIO_CLK(0x1) |
+ DSI_PAD_CONTROL_PAD_PULLDN_ENAB(TEGRA_DSI_ENABLE);
+ tegra_dsi_writel(dsi, val, DSI_PAD_CONTROL);
+
+ /* Suspend core-logic */
+ val = DSI_POWER_CONTROL_LEG_DSI_ENABLE(TEGRA_DSI_DISABLE);
+ tegra_dsi_writel(dsi, val, DSI_POWER_CONTROL);
+ case DSI_HOST_SUSPEND_LV1:
+ /* Disable dsi fast and slow clock */
+ tegra_dsi_config_phy_clk(dsi, TEGRA_DSI_DISABLE);
+ case DSI_HOST_SUSPEND_LV0:
+ /* Disable dsi source clock */
+ tegra_dsi_clk_disable(dsi);
+ break;
+ case DSI_NO_SUSPEND:
+ break;
+ default:
+ dev_err(&dc->ndev->dev, "DSI suspend aggressiveness"
+ "is not supported.\n");
}
- /*
- * Suspend pad
- * It is ok to overwrite previous value of DSI_PAD_CONTROL reg
- * because it will be restored properly in resume sequence
- */
- val = DSI_PAD_CONTROL_PAD_PDIO(0x3) |
- DSI_PAD_CONTROL_PAD_PDIO_CLK(0x1) |
- DSI_PAD_CONTROL_PAD_PULLDN_ENAB(TEGRA_DSI_ENABLE);
- tegra_dsi_writel(dsi, val, DSI_PAD_CONTROL);
+ dsi->enabled = false;
- /* Suspend core-logic */
- val = DSI_POWER_CONTROL_LEG_DSI_ENABLE(TEGRA_DSI_DISABLE);
- tegra_dsi_writel(dsi, val, DSI_POWER_CONTROL);
+ return 0;
+fail:
+ return err;
+}
- /* Disable dsi fast and slow clock */
- parent_clk = clk_get_parent(dsi->dsi_clk);
- base_clk = clk_get_parent(parent_clk);
- if (dsi->info.dsi_instance)
- tegra_clk_cfg_ex(base_clk,
- TEGRA_CLK_PLLD_CSI_OUT_ENB,
- 0);
- else
- tegra_clk_cfg_ex(base_clk,
- TEGRA_CLK_PLLD_DSI_OUT_ENB,
- 0);
- /* Disable dsi source clock */
- clk_disable(dsi->dsi_clk);
+int tegra_dsi_host_suspend(struct tegra_dc *dc)
+{
+ int err = 0;
+ struct tegra_dc_dsi_data *dsi = tegra_dc_get_outdata(dc);
- dsi->clk_ref = false;
- dsi->enabled = false;
+ if (dsi->host_suspended)
+ return 0;
- return 0;
+ tegra_dsi_stop_dc_stream(dc, dsi);
+
+ err = tegra_dsi_deep_sleep(dc, dsi, dsi->info.suspend_aggr);
+ if (err < 0)
+ dev_err(&dc->ndev->dev,
+ "DSI failed to enter deep sleep\n");
+
+ dsi->host_suspended = true;
+
+ return err;
+}
+
+
+int tegra_dsi_host_resume(struct tegra_dc *dc)
+{
+ int val = 0;
+ int err = 0;
+ struct tegra_dc_dsi_data *dsi = tegra_dc_get_outdata(dc);
+
+ if (!dsi->host_suspended)
+ return 0;
+
+ switch (dsi->info.suspend_aggr) {
+ case DSI_HOST_SUSPEND_LV0:
+ tegra_dsi_clk_enable(dsi);
+ break;
+ case DSI_HOST_SUSPEND_LV1:
+ tegra_dsi_config_phy_clk(dsi, TEGRA_DSI_ENABLE);
+ tegra_dsi_clk_enable(dsi);
+ break;
+ case DSI_HOST_SUSPEND_LV2:
+ tegra_dsi_config_phy_clk(dsi, TEGRA_DSI_ENABLE);
+ tegra_dsi_clk_enable(dsi);
+
+ tegra_dsi_writel(dsi,
+ DSI_POWER_CONTROL_LEG_DSI_ENABLE(TEGRA_DSI_ENABLE),
+ DSI_POWER_CONTROL);
+
+ if (dsi->ulpm) {
+ err = tegra_dsi_enter_ulpm(dsi);
+ if (err < 0) {
+ dev_err(&dc->ndev->dev,
+ "DSI failed to enter ulpm\n");
+ goto fail;
+ }
+
+ val = tegra_dsi_readl(dsi, DSI_PAD_CONTROL);
+ val &= ~(DSI_PAD_CONTROL_PAD_PDIO(0x3) |
+ DSI_PAD_CONTROL_PAD_PDIO_CLK(0x1) |
+ DSI_PAD_CONTROL_PAD_PULLDN_ENAB(0x1));
+ tegra_dsi_writel(dsi, val, DSI_PAD_CONTROL);
+
+ if (tegra_dsi_exit_ulpm(dsi) < 0) {
+ dev_err(&dc->ndev->dev,
+ "DSI failed to exit ulpm\n");
+ goto fail;
+ }
+ }
+ break;
+ case DSI_NO_SUSPEND:
+ break;
+ default:
+ dev_err(&dc->ndev->dev, "DSI suspend aggressivenes"
+ "is not supported.\n");
+ }
+
+ dsi->enabled = true;
+ dsi->host_suspended = false;
+ tegra_dsi_start_dc_stream(dc, dsi);
fail:
return err;
}
@@ -3071,7 +3273,7 @@ static void tegra_dc_dsi_disable(struct tegra_dc *dc)
tegra_dsi_stop_dc_stream_at_frame_end(dc, dsi);
if (dsi->info.power_saving_suspend) {
- if (tegra_dsi_deep_sleep(dc, dsi) < 0) {
+ if (tegra_dsi_deep_sleep(dc, dsi, DSI_SUSPEND_FULL) < 0) {
dev_err(&dc->ndev->dev,
"DSI failed to enter deep sleep\n");
goto fail;
@@ -3124,7 +3326,7 @@ static void tegra_dc_dsi_suspend(struct tegra_dc *dc)
}
}
- if (tegra_dsi_deep_sleep(dc, dsi) < 0) {
+ if (tegra_dsi_deep_sleep(dc, dsi, DSI_SUSPEND_FULL) < 0) {
dev_err(&dc->ndev->dev,
"DSI failed to enter deep sleep\n");
goto fail;
diff --git a/drivers/video/tegra/dc/dsi.h b/drivers/video/tegra/dc/dsi.h
index 18ea9c959e8d..bf54913a1794 100644
--- a/drivers/video/tegra/dc/dsi.h
+++ b/drivers/video/tegra/dc/dsi.h
@@ -1,18 +1,18 @@
/*
- * drivers/video/tegra/dc/dsi.h
- *
- * Copyright (c) 2011, NVIDIA Corporation.
- *
- * 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.
- *
- */
+ * drivers/video/tegra/dc/dsi.h
+ *
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION, 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 __DRIVERS_VIDEO_TEGRA_DC_DSI_H__
#define __DRIVERS_VIDEO_TEGRA_DC_DSI_H__
diff --git a/drivers/video/tegra/dc/dsi_regs.h b/drivers/video/tegra/dc/dsi_regs.h
index 203ac32bd92d..71045fcec29e 100644
--- a/drivers/video/tegra/dc/dsi_regs.h
+++ b/drivers/video/tegra/dc/dsi_regs.h
@@ -1,18 +1,18 @@
/*
- * drivers/video/tegra/dc/dsi_regs.h
- *
- * Copyright (c) 2011, NVIDIA Corporation.
- *
- * 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.
- *
- */
+ * drivers/video/tegra/dc/dsi_regs.h
+ *
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION, 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 __DRIVERS_VIDEO_TEGRA_DC_DSI_REG_H__
#define __DRIVERS_VIDEO_TEGRA_DC_DSI_REG_H__
diff --git a/drivers/video/tegra/dc/edid.c b/drivers/video/tegra/dc/edid.c
index 8776c5393410..b1de7ab1dfb5 100644
--- a/drivers/video/tegra/dc/edid.c
+++ b/drivers/video/tegra/dc/edid.c
@@ -4,7 +4,7 @@
* Copyright (C) 2010 Google, Inc.
* Author: Erik Gilling <konkers@android.com>
*
- * Copyright (C) 2010-2011 NVIDIA Corporation
+ * Copyright (c) 2010-2012, NVIDIA CORPORATION, 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
diff --git a/drivers/video/tegra/dc/ext/Makefile b/drivers/video/tegra/dc/ext/Makefile
index 19860ab5db11..16e4cdf43ebb 100644
--- a/drivers/video/tegra/dc/ext/Makefile
+++ b/drivers/video/tegra/dc/ext/Makefile
@@ -1,3 +1,5 @@
+GCOV_PROFILE := y
+EXTRA_CFLAGS += -Idrivers/video/tegra/host
obj-y += dev.o
obj-y += util.o
obj-y += cursor.o
diff --git a/drivers/video/tegra/dc/ext/control.c b/drivers/video/tegra/dc/ext/control.c
index 9caf3e11c16c..ed812be2eab5 100644
--- a/drivers/video/tegra/dc/ext/control.c
+++ b/drivers/video/tegra/dc/ext/control.c
@@ -1,7 +1,7 @@
/*
* drivers/video/tegra/dc/ext/control.c
*
- * Copyright (C) 2011, NVIDIA Corporation
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION, All rights reserved.
*
* Author: Robert Morell <rmorell@nvidia.com>
*
@@ -67,7 +67,7 @@ static int get_output_edid(struct tegra_dc_ext_control_output_edid *edid)
struct tegra_dc *dc;
size_t user_size = edid->size;
struct tegra_dc_edid *dc_edid = NULL;
- int ret;
+ int ret = 0;
/* TODO: this should be more dynamic */
if (edid->handle > 2)
@@ -262,10 +262,7 @@ int tegra_dc_ext_control_init(void)
return ret;
control->dev = device_create(tegra_dc_ext_class,
- NULL,
- tegra_dc_ext_devno,
- NULL,
- "tegra_dc_ctrl");
+ NULL, tegra_dc_ext_devno, NULL, "tegra_dc_ctrl");
if (IS_ERR(control->dev)) {
ret = PTR_ERR(control->dev);
cdev_del(&control->cdev);
diff --git a/drivers/video/tegra/dc/ext/cursor.c b/drivers/video/tegra/dc/ext/cursor.c
index d8fa5fd8e6d9..970f38f5ac09 100644
--- a/drivers/video/tegra/dc/ext/cursor.c
+++ b/drivers/video/tegra/dc/ext/cursor.c
@@ -1,7 +1,7 @@
/*
* drivers/video/tegra/dc/ext/cursor.c
*
- * Copyright (C) 2011, NVIDIA Corporation
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION, All rights reserved.
*
* Author: Robert Morell <rmorell@nvidia.com>
*
diff --git a/drivers/video/tegra/dc/ext/dev.c b/drivers/video/tegra/dc/ext/dev.c
index 04553e778390..f9c76f8f0d0d 100644
--- a/drivers/video/tegra/dc/ext/dev.c
+++ b/drivers/video/tegra/dc/ext/dev.c
@@ -1,7 +1,7 @@
/*
* drivers/video/tegra/dc/dev.c
*
- * Copyright (C) 2011-2012, NVIDIA Corporation
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION, All rights reserved.
*
* Author: Robert Morell <rmorell@nvidia.com>
* Some code based on fbdev extensions written by:
@@ -27,11 +27,12 @@
#include <video/tegra_dc_ext.h>
#include <mach/dc.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include <mach/tegra_dc_ext.h>
/* XXX ew */
#include "../dc_priv.h"
+#include "../dc_config.h"
/* XXX ew 2 */
#include "../../host/dev.h"
/* XXX ew 3 */
@@ -172,10 +173,39 @@ void tegra_dc_ext_disable(struct tegra_dc_ext *ext)
}
}
+int tegra_dc_ext_check_windowattr(struct tegra_dc_ext *ext,
+ struct tegra_dc_win *win)
+{
+ long *addr;
+ struct tegra_dc *dc = ext->dc;
+
+ /* Check the window format */
+ addr = tegra_dc_parse_feature(dc, win->idx, GET_WIN_FORMATS);
+ if (!test_bit(win->fmt, addr)) {
+ dev_err(&dc->ndev->dev, "Color format of window %d is"
+ " invalid.\n", win->idx);
+ goto fail;
+ }
+
+ /* Check window size */
+ addr = tegra_dc_parse_feature(dc, win->idx, GET_WIN_SIZE);
+ if (CHECK_SIZE(win->out_w, addr[MIN_WIDTH], addr[MAX_WIDTH]) ||
+ CHECK_SIZE(win->out_h, addr[MIN_HEIGHT], addr[MAX_HEIGHT])) {
+ dev_err(&dc->ndev->dev, "Size of window %d is"
+ " invalid.\n", win->idx);
+ goto fail;
+ }
+
+ return 0;
+fail:
+ return -EINVAL;
+}
+
static int tegra_dc_ext_set_windowattr(struct tegra_dc_ext *ext,
struct tegra_dc_win *win,
const struct tegra_dc_ext_flip_win *flip_win)
{
+ int err = 0;
struct tegra_dc_ext_win *ext_win = &ext->win[win->idx];
if (flip_win->handle[TEGRA_DC_Y] == NULL) {
@@ -195,6 +225,10 @@ static int tegra_dc_ext_set_windowattr(struct tegra_dc_ext *ext,
win->flags |= TEGRA_WIN_FLAG_INVERT_H;
if (flip_win->attr.flags & TEGRA_DC_EXT_FLIP_FLAG_INVERT_V)
win->flags |= TEGRA_WIN_FLAG_INVERT_V;
+ if (flip_win->attr.flags & TEGRA_DC_EXT_FLIP_FLAG_GLOBAL_ALPHA)
+ win->global_alpha = flip_win->attr.global_alpha;
+ else
+ win->global_alpha = 255;
win->fmt = flip_win->attr.pixformat;
win->x.full = flip_win->attr.x;
win->y.full = flip_win->attr.y;
@@ -223,6 +257,11 @@ static int tegra_dc_ext_set_windowattr(struct tegra_dc_ext *ext,
win->stride = flip_win->attr.stride;
win->stride_uv = flip_win->attr.stride_uv;
+ err = tegra_dc_ext_check_windowattr(ext, win);
+ if (err < 0)
+ dev_err(&ext->dc->ndev->dev,
+ "Window atrributes are invalid.\n");
+
if ((s32)flip_win->attr.pre_syncpt_id >= 0) {
nvhost_syncpt_wait_timeout(
&nvhost_get_host(ext->dc->ndev)->syncpt,
@@ -408,7 +447,7 @@ static int tegra_dc_ext_flip(struct tegra_dc_ext_user *user,
{
struct tegra_dc_ext *ext = user->ext;
struct tegra_dc_ext_flip_data *data;
- int work_index;
+ int work_index = -1;
int i, ret = 0;
#ifdef CONFIG_ANDROID
@@ -520,6 +559,10 @@ static int tegra_dc_ext_flip(struct tegra_dc_ext_user *user,
atomic_inc(&ext->win[work_index].nr_pending_flips);
}
+ if (work_index < 0) {
+ ret = -EINVAL;
+ goto unlock;
+ }
queue_work(ext->win[work_index].flip_wq, &data->work);
unlock_windows_for_flip(user, args);
@@ -669,6 +712,21 @@ static int tegra_dc_ext_get_status(struct tegra_dc_ext_user *user,
return 0;
}
+static int tegra_dc_ext_get_feature(struct tegra_dc_ext_user *user,
+ struct tegra_dc_ext_feature *feature)
+{
+ struct tegra_dc *dc = user->ext->dc;
+ struct tegra_dc_feature *table = dc->feature;
+
+ if (dc->enabled && feature->entries) {
+ feature->length = table->num_entries;
+ memcpy(feature->entries, table->entries, table->num_entries *
+ sizeof(struct tegra_dc_feature_entry));
+ }
+
+ return 0;
+}
+
static long tegra_dc_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
@@ -766,6 +824,22 @@ static long tegra_dc_ioctl(struct file *filp, unsigned int cmd,
return tegra_dc_ext_set_lut(user, &args);
}
+ case TEGRA_DC_EXT_GET_FEATURES:
+ {
+ struct tegra_dc_ext_feature args;
+ int ret;
+
+ if (copy_from_user(&args, user_arg, sizeof(args)))
+ return -EFAULT;
+
+ ret = tegra_dc_ext_get_feature(user, &args);
+
+ if (copy_to_user(user_arg, &args, sizeof(args)))
+ return -EFAULT;
+
+ return ret;
+ }
+
default:
return -EINVAL;
}
diff --git a/drivers/video/tegra/dc/ext/events.c b/drivers/video/tegra/dc/ext/events.c
index 150a1501fced..577d056e2436 100644
--- a/drivers/video/tegra/dc/ext/events.c
+++ b/drivers/video/tegra/dc/ext/events.c
@@ -1,7 +1,7 @@
/*
* drivers/video/tegra/dc/ext/events.c
*
- * Copyright (C) 2011, NVIDIA Corporation
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION, All rights reserved.
*
* Author: Robert Morell <rmorell@nvidia.com>
*
diff --git a/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h b/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h
index 95a637d5a52a..f68c7d5c93c2 100644
--- a/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h
+++ b/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h
@@ -1,7 +1,7 @@
/*
* drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h
*
- * Copyright (C) 2011, NVIDIA Corporation
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION, All rights reserved.
*
* Author: Robert Morell <rmorell@nvidia.com>
*
@@ -25,7 +25,7 @@
#include <linux/poll.h>
#include <mach/dc.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include <video/tegra_dc_ext.h>
diff --git a/drivers/video/tegra/dc/ext/util.c b/drivers/video/tegra/dc/ext/util.c
index 747085579f15..bd8b3c012c0e 100644
--- a/drivers/video/tegra/dc/ext/util.c
+++ b/drivers/video/tegra/dc/ext/util.c
@@ -1,7 +1,7 @@
/*
* drivers/video/tegra/dc/ext/util.c
*
- * Copyright (C) 2011, NVIDIA Corporation
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION, All rights reserved.
*
* Author: Robert Morell <rmorell@nvidia.com>
*
@@ -20,7 +20,7 @@
#include <linux/types.h>
#include <mach/dc.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
/* ugh */
#include "../../nvmap/nvmap.h"
diff --git a/drivers/video/tegra/dc/hdmi.c b/drivers/video/tegra/dc/hdmi.c
index 6a7cfaea6672..79478ea48f83 100644
--- a/drivers/video/tegra/dc/hdmi.c
+++ b/drivers/video/tegra/dc/hdmi.c
@@ -4,7 +4,7 @@
* Copyright (C) 2010 Google, Inc.
* Author: Erik Gilling <konkers@android.com>
*
- * Copyright (C) 2010-2011 NVIDIA Corporation
+ * Copyright (c) 2010-2012, NVIDIA CORPORATION, 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
@@ -1213,22 +1213,6 @@ static int tegra_dc_calc_clock_per_frame(const struct fb_videomode *mode)
(mode->upper_margin + mode->yres +
mode->lower_margin + mode->vsync_len);
}
-static bool tegra_dc_hdmi_mode_equal(const struct fb_videomode *mode1,
- const struct fb_videomode *mode2)
-{
- int clock_per_frame1 = tegra_dc_calc_clock_per_frame(mode1);
- int clock_per_frame2 = tegra_dc_calc_clock_per_frame(mode2);
-
- /* allows up to 1Hz of pixclock difference */
- return (clock_per_frame1 == clock_per_frame2 &&
- mode1->xres == mode2->xres &&
- mode1->yres == mode2->yres &&
- mode1->vmode == mode2->vmode &&
- (mode1->pixclock == mode2->pixclock ||
- (abs(PICOS2KHZ(mode1->pixclock) -
- PICOS2KHZ(mode2->pixclock)) *
- 1000 / clock_per_frame1 <= 1)));
-}
static bool tegra_dc_hdmi_valid_pixclock(const struct tegra_dc *dc,
const struct fb_videomode *mode)
@@ -1515,10 +1499,10 @@ static void tegra_dc_hdmi_resume(struct tegra_dc *dc)
tegra_nvhdcp_resume(hdmi->nvhdcp);
}
+#ifdef CONFIG_SWITCH
static ssize_t underscan_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
-#ifdef CONFIG_SWITCH
struct tegra_dc_hdmi_data *hdmi =
container_of(dev_get_drvdata(dev), struct tegra_dc_hdmi_data, hpd_switch);
@@ -1526,19 +1510,19 @@ static ssize_t underscan_show(struct device *dev,
return sprintf(buf, "%d\n", tegra_edid_underscan_supported(hdmi->edid));
else
return 0;
-#else
- return 0;
-#endif
}
static DEVICE_ATTR(underscan, S_IRUGO | S_IWUSR, underscan_show, NULL);
+#endif
static int tegra_dc_hdmi_init(struct tegra_dc *dc)
{
struct tegra_dc_hdmi_data *hdmi;
struct resource *res;
struct resource *base_res;
+#ifdef CONFIG_SWITCH
int ret;
+#endif
void __iomem *base;
struct clk *clk = NULL;
struct clk *disp1_clk = NULL;
@@ -1685,8 +1669,10 @@ static int tegra_dc_hdmi_init(struct tegra_dc *dc)
return 0;
+#ifdef CONFIG_TEGRA_NVHDCP
err_edid_destroy:
tegra_edid_destroy(hdmi->edid);
+#endif
err_free_irq:
free_irq(gpio_to_irq(dc->out->hotplug_gpio), dc);
err_put_clock:
@@ -2082,6 +2068,11 @@ static void tegra_dc_hdmi_setup_avi_infoframe(struct tegra_dc *dc, bool dvi)
avi.r = HDMI_AVI_R_SAME;
+ if ((dc->mode.h_active == 720) && ((dc->mode.v_active == 480) || (dc->mode.v_active == 576)))
+ tegra_dc_writel(dc, 0x00101010, DC_DISP_BORDER_COLOR);
+ else
+ tegra_dc_writel(dc, 0x00000000, DC_DISP_BORDER_COLOR);
+
if (dc->mode.v_active == 480) {
if (dc->mode.h_active == 640) {
avi.m = HDMI_AVI_M_4_3;
@@ -2114,9 +2105,12 @@ static void tegra_dc_hdmi_setup_avi_infoframe(struct tegra_dc *dc, bool dvi)
(dc->mode.v_active == 2205 && dc->mode.stereo_mode)) {
/* VIC for both 1080p and 1080p 3D mode */
avi.m = HDMI_AVI_M_16_9;
- if (dc->mode.h_front_porch == 88)
- avi.vic = 16; /* 60 Hz */
- else if (dc->mode.h_front_porch == 528)
+ if (dc->mode.h_front_porch == 88) {
+ if (dc->mode.pclk > 74250000)
+ avi.vic = 16; /* 60 Hz */
+ else
+ avi.vic = 34; /* 30 Hz */
+ } else if (dc->mode.h_front_porch == 528)
avi.vic = 31; /* 50 Hz */
else
avi.vic = 32; /* 24 Hz */
@@ -2277,10 +2271,16 @@ static void tegra_dc_hdmi_enable(struct tegra_dc *dc)
VSYNC_WINDOW_ENABLE,
HDMI_NV_PDISP_HDMI_VSYNC_WINDOW);
- tegra_hdmi_writel(hdmi,
- (dc->ndev->id ? HDMI_SRC_DISPLAYB : HDMI_SRC_DISPLAYA) |
- ARM_VIDEO_RANGE_LIMITED,
- HDMI_NV_PDISP_INPUT_CONTROL);
+ if ((dc->mode.h_active == 720) && ((dc->mode.v_active == 480) || (dc->mode.v_active == 576)))
+ tegra_hdmi_writel(hdmi,
+ (dc->ndev->id ? HDMI_SRC_DISPLAYB : HDMI_SRC_DISPLAYA) |
+ ARM_VIDEO_RANGE_FULL,
+ HDMI_NV_PDISP_INPUT_CONTROL);
+ else
+ tegra_hdmi_writel(hdmi,
+ (dc->ndev->id ? HDMI_SRC_DISPLAYB : HDMI_SRC_DISPLAYA) |
+ ARM_VIDEO_RANGE_LIMITED,
+ HDMI_NV_PDISP_INPUT_CONTROL);
clk_disable(hdmi->disp1_clk);
clk_disable(hdmi->disp2_clk);
diff --git a/drivers/video/tegra/dc/hdmi.h b/drivers/video/tegra/dc/hdmi.h
index 702ab16e87f0..5b4c42a31ffa 100644
--- a/drivers/video/tegra/dc/hdmi.h
+++ b/drivers/video/tegra/dc/hdmi.h
@@ -6,7 +6,7 @@
* Copyright (C) 2010 Google, Inc.
* Author: Erik Gilling <konkers@android.com>
*
- * Copyright (C) 2010-2011 NVIDIA Corporation
+ * Copyright (c) 2010-2012, NVIDIA CORPORATION, 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
diff --git a/drivers/video/tegra/dc/hdmi_reg.h b/drivers/video/tegra/dc/hdmi_reg.h
index 0bdda43199e3..4a5fdcb2aaa6 100644
--- a/drivers/video/tegra/dc/hdmi_reg.h
+++ b/drivers/video/tegra/dc/hdmi_reg.h
@@ -4,6 +4,8 @@
* Copyright (C) 2010 Google, Inc.
* Author: Erik Gilling <konkers@android.com>
*
+ * Copyright (c) 2010-2012, NVIDIA CORPORATION, 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.
diff --git a/drivers/video/tegra/dc/lut.c b/drivers/video/tegra/dc/lut.c
new file mode 100644
index 000000000000..7ce8fc6768a0
--- /dev/null
+++ b/drivers/video/tegra/dc/lut.c
@@ -0,0 +1,130 @@
+/*
+ * drivers/video/tegra/dc/lut.c
+ *
+ * Copyright (c) 2010-2012, NVIDIA CORPORATION, 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/err.h>
+#include <linux/types.h>
+#include <mach/dc.h>
+
+#include "dc_reg.h"
+#include "dc_priv.h"
+
+void tegra_dc_init_lut_defaults(struct tegra_dc_lut *lut)
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ lut->r[i] = lut->g[i] = lut->b[i] = (u8)i;
+}
+
+static int tegra_dc_loop_lut(struct tegra_dc *dc,
+ struct tegra_dc_win *win,
+ int(*lambda)(struct tegra_dc *dc, int i, u32 rgb))
+{
+ struct tegra_dc_lut *lut = &win->lut;
+ struct tegra_dc_lut *global_lut = &dc->fb_lut;
+ int i;
+ for (i = 0; i < 256; i++) {
+
+ u32 r = (u32)lut->r[i];
+ u32 g = (u32)lut->g[i];
+ u32 b = (u32)lut->b[i];
+
+ if (!(win->ppflags & TEGRA_WIN_PPFLAG_CP_FBOVERRIDE)) {
+ r = (u32)global_lut->r[r];
+ g = (u32)global_lut->g[g];
+ b = (u32)global_lut->b[b];
+ }
+
+ if (!lambda(dc, i, r | (g<<8) | (b<<16)))
+ return 0;
+ }
+ return 1;
+}
+
+static int tegra_dc_lut_isdefaults_lambda(struct tegra_dc *dc, int i, u32 rgb)
+{
+ if (rgb != (i | (i<<8) | (i<<16)))
+ return 0;
+ return 1;
+}
+
+static int tegra_dc_set_lut_setreg_lambda(struct tegra_dc *dc, int i, u32 rgb)
+{
+ tegra_dc_writel(dc, rgb, DC_WIN_COLOR_PALETTE(i));
+ return 1;
+}
+
+void tegra_dc_set_lut(struct tegra_dc *dc, struct tegra_dc_win *win)
+{
+ unsigned long val = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS);
+
+ tegra_dc_loop_lut(dc, win, tegra_dc_set_lut_setreg_lambda);
+
+ if (win->ppflags & TEGRA_WIN_PPFLAG_CP_ENABLE)
+ val |= CP_ENABLE;
+ else
+ val &= ~CP_ENABLE;
+
+ tegra_dc_writel(dc, val, DC_WIN_WIN_OPTIONS);
+}
+
+static int tegra_dc_update_winlut(struct tegra_dc *dc, int win_idx, int fbovr)
+{
+ struct tegra_dc_win *win = &dc->windows[win_idx];
+
+ mutex_lock(&dc->lock);
+
+ if (!dc->enabled) {
+ mutex_unlock(&dc->lock);
+ return -EFAULT;
+ }
+
+ if (fbovr > 0)
+ win->ppflags |= TEGRA_WIN_PPFLAG_CP_FBOVERRIDE;
+ else if (fbovr == 0)
+ win->ppflags &= ~TEGRA_WIN_PPFLAG_CP_FBOVERRIDE;
+
+ if (!tegra_dc_loop_lut(dc, win, tegra_dc_lut_isdefaults_lambda))
+ win->ppflags |= TEGRA_WIN_PPFLAG_CP_ENABLE;
+ else
+ win->ppflags &= ~TEGRA_WIN_PPFLAG_CP_ENABLE;
+
+ tegra_dc_writel(dc, WINDOW_A_SELECT << win_idx,
+ DC_CMD_DISPLAY_WINDOW_HEADER);
+
+ tegra_dc_set_lut(dc, win);
+
+ mutex_unlock(&dc->lock);
+
+ tegra_dc_update_windows(&win, 1);
+
+ return 0;
+}
+
+int tegra_dc_update_lut(struct tegra_dc *dc, int win_idx, int fboveride)
+{
+ if (win_idx > -1)
+ return tegra_dc_update_winlut(dc, win_idx, fboveride);
+
+ for (win_idx = 0; win_idx < DC_N_WINDOWS; win_idx++) {
+ int err = tegra_dc_update_winlut(dc, win_idx, fboveride);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(tegra_dc_update_lut);
+
diff --git a/drivers/video/tegra/dc/mode.c b/drivers/video/tegra/dc/mode.c
new file mode 100644
index 000000000000..49cc5f5abd53
--- /dev/null
+++ b/drivers/video/tegra/dc/mode.c
@@ -0,0 +1,318 @@
+/*
+ * drivers/video/tegra/dc/mode.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * Copyright (c) 2010-2012, NVIDIA CORPORATION, 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/err.h>
+#include <linux/types.h>
+#include <linux/clk.h>
+
+#include <mach/clk.h>
+#include <mach/dc.h>
+
+#include "dc_reg.h"
+#include "dc_priv.h"
+
+/* return non-zero if constraint is violated */
+static int calc_h_ref_to_sync(const struct tegra_dc_mode *mode, int *href)
+{
+ long a, b;
+
+ /* Constraint 5: H_REF_TO_SYNC >= 0 */
+ a = 0;
+
+ /* Constraint 6: H_FRONT_PORT >= (H_REF_TO_SYNC + 1) */
+ b = mode->h_front_porch - 1;
+
+ /* Constraint 1: H_REF_TO_SYNC + H_SYNC_WIDTH + H_BACK_PORCH > 11 */
+ if (a + mode->h_sync_width + mode->h_back_porch <= 11)
+ a = 1 + 11 - mode->h_sync_width - mode->h_back_porch;
+ /* check Constraint 1 and 6 */
+ if (a > b)
+ return 1;
+
+ /* Constraint 4: H_SYNC_WIDTH >= 1 */
+ if (mode->h_sync_width < 1)
+ return 4;
+
+ /* Constraint 7: H_DISP_ACTIVE >= 16 */
+ if (mode->h_active < 16)
+ return 7;
+
+ if (href) {
+ if (b > a && a % 2)
+ *href = a + 1; /* use smallest even value */
+ else
+ *href = a; /* even or only possible value */
+ }
+
+ return 0;
+}
+
+static int calc_v_ref_to_sync(const struct tegra_dc_mode *mode, int *vref)
+{
+ long a;
+ a = 1; /* Constraint 5: V_REF_TO_SYNC >= 1 */
+
+ /* Constraint 2: V_REF_TO_SYNC + V_SYNC_WIDTH + V_BACK_PORCH > 1 */
+ if (a + mode->v_sync_width + mode->v_back_porch <= 1)
+ a = 1 + 1 - mode->v_sync_width - mode->v_back_porch;
+
+ /* Constraint 6 */
+ if (mode->v_front_porch < a + 1)
+ a = mode->v_front_porch - 1;
+
+ /* Constraint 4: V_SYNC_WIDTH >= 1 */
+ if (mode->v_sync_width < 1)
+ return 4;
+
+ /* Constraint 7: V_DISP_ACTIVE >= 16 */
+ if (mode->v_active < 16)
+ return 7;
+
+ if (vref)
+ *vref = a;
+ return 0;
+}
+
+static int calc_ref_to_sync(struct tegra_dc_mode *mode)
+{
+ int ret;
+ ret = calc_h_ref_to_sync(mode, &mode->h_ref_to_sync);
+ if (ret)
+ return ret;
+ ret = calc_v_ref_to_sync(mode, &mode->v_ref_to_sync);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static bool check_ref_to_sync(struct tegra_dc_mode *mode)
+{
+ /* Constraint 1: H_REF_TO_SYNC + H_SYNC_WIDTH + H_BACK_PORCH > 11. */
+ if (mode->h_ref_to_sync + mode->h_sync_width + mode->h_back_porch <= 11)
+ return false;
+
+ /* Constraint 2: V_REF_TO_SYNC + V_SYNC_WIDTH + V_BACK_PORCH > 1. */
+ if (mode->v_ref_to_sync + mode->v_sync_width + mode->v_back_porch <= 1)
+ return false;
+
+ /* Constraint 3: V_FRONT_PORCH + V_SYNC_WIDTH + V_BACK_PORCH > 1
+ * (vertical blank). */
+ if (mode->v_front_porch + mode->v_sync_width + mode->v_back_porch <= 1)
+ return false;
+
+ /* Constraint 4: V_SYNC_WIDTH >= 1; H_SYNC_WIDTH >= 1. */
+ if (mode->v_sync_width < 1 || mode->h_sync_width < 1)
+ return false;
+
+ /* Constraint 5: V_REF_TO_SYNC >= 1; H_REF_TO_SYNC >= 0. */
+ if (mode->v_ref_to_sync < 1 || mode->h_ref_to_sync < 0)
+ return false;
+
+ /* Constraint 6: V_FRONT_PORT >= (V_REF_TO_SYNC + 1);
+ * H_FRONT_PORT >= (H_REF_TO_SYNC + 1). */
+ if (mode->v_front_porch < mode->v_ref_to_sync + 1 ||
+ mode->h_front_porch < mode->h_ref_to_sync + 1)
+ return false;
+
+ /* Constraint 7: H_DISP_ACTIVE >= 16; V_DISP_ACTIVE >= 16. */
+ if (mode->h_active < 16 || mode->v_active < 16)
+ return false;
+
+ return true;
+}
+
+/* return in 1000ths of a Hertz */
+int tegra_dc_calc_refresh(const struct tegra_dc_mode *m)
+{
+ long h_total, v_total, refresh;
+ h_total = m->h_active + m->h_front_porch + m->h_back_porch +
+ m->h_sync_width;
+ v_total = m->v_active + m->v_front_porch + m->v_back_porch +
+ m->v_sync_width;
+ refresh = m->pclk / h_total;
+ refresh *= 1000;
+ refresh /= v_total;
+ return refresh;
+}
+
+#ifdef DEBUG
+static void print_mode(struct tegra_dc *dc,
+ const struct tegra_dc_mode *mode, const char *note)
+{
+ if (mode) {
+ int refresh = tegra_dc_calc_refresh(mode);
+ dev_info(&dc->ndev->dev, "%s():MODE:%dx%d@%d.%03uHz pclk=%d\n",
+ note ? note : "",
+ mode->h_active, mode->v_active,
+ refresh / 1000, refresh % 1000,
+ mode->pclk);
+ }
+}
+#else /* !DEBUG */
+static inline void print_mode(struct tegra_dc *dc,
+ const struct tegra_dc_mode *mode, const char *note) { }
+#endif /* DEBUG */
+
+int tegra_dc_program_mode(struct tegra_dc *dc, struct tegra_dc_mode *mode)
+{
+ unsigned long val;
+ unsigned long rate;
+ unsigned long div;
+ unsigned long pclk;
+
+ print_mode(dc, mode, __func__);
+
+ /* use default EMC rate when switching modes */
+ dc->new_emc_clk_rate = tegra_dc_get_default_emc_clk_rate(dc);
+ tegra_dc_program_bandwidth(dc, true);
+
+ tegra_dc_writel(dc, 0x0, DC_DISP_DISP_TIMING_OPTIONS);
+ tegra_dc_writel(dc, mode->h_ref_to_sync | (mode->v_ref_to_sync << 16),
+ DC_DISP_REF_TO_SYNC);
+ tegra_dc_writel(dc, mode->h_sync_width | (mode->v_sync_width << 16),
+ DC_DISP_SYNC_WIDTH);
+ tegra_dc_writel(dc, mode->h_back_porch | (mode->v_back_porch << 16),
+ DC_DISP_BACK_PORCH);
+ tegra_dc_writel(dc, mode->h_active | (mode->v_active << 16),
+ DC_DISP_DISP_ACTIVE);
+ tegra_dc_writel(dc, mode->h_front_porch | (mode->v_front_porch << 16),
+ DC_DISP_FRONT_PORCH);
+
+ tegra_dc_writel(dc, DE_SELECT_ACTIVE | DE_CONTROL_NORMAL,
+ DC_DISP_DATA_ENABLE_OPTIONS);
+
+ /* TODO: MIPI/CRT/HDMI clock cals */
+
+ val = DISP_DATA_FORMAT_DF1P1C;
+
+ if (dc->out->align == TEGRA_DC_ALIGN_MSB)
+ val |= DISP_DATA_ALIGNMENT_MSB;
+ else
+ val |= DISP_DATA_ALIGNMENT_LSB;
+
+ if (dc->out->order == TEGRA_DC_ORDER_RED_BLUE)
+ val |= DISP_DATA_ORDER_RED_BLUE;
+ else
+ val |= DISP_DATA_ORDER_BLUE_RED;
+
+ tegra_dc_writel(dc, val, DC_DISP_DISP_INTERFACE_CONTROL);
+
+ rate = tegra_dc_clk_get_rate(dc);
+
+ pclk = tegra_dc_pclk_round_rate(dc, mode->pclk);
+ trace_printk("%s:pclk=%ld\n", dc->ndev->name, pclk);
+ if (pclk < (mode->pclk / 100 * 99) ||
+ pclk > (mode->pclk / 100 * 109)) {
+ dev_err(&dc->ndev->dev,
+ "can't divide %ld clock to %d -1/+9%% %ld %d %d\n",
+ rate, mode->pclk,
+ pclk, (mode->pclk / 100 * 99),
+ (mode->pclk / 100 * 109));
+ return -EINVAL;
+ }
+
+ div = (rate * 2 / pclk) - 2;
+ trace_printk("%s:div=%ld\n", dc->ndev->name, div);
+
+ tegra_dc_writel(dc, 0x00010001,
+ DC_DISP_SHIFT_CLOCK_OPTIONS);
+ tegra_dc_writel(dc, PIXEL_CLK_DIVIDER_PCD1 | SHIFT_CLK_DIVIDER(div),
+ DC_DISP_DISP_CLOCK_CONTROL);
+
+#ifdef CONFIG_SWITCH
+ switch_set_state(&dc->modeset_switch,
+ (mode->h_active << 16) | mode->v_active);
+#endif
+
+ tegra_dc_writel(dc, GENERAL_UPDATE, DC_CMD_STATE_CONTROL);
+ tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
+
+ print_mode_info(dc, dc->mode);
+ return 0;
+}
+
+int tegra_dc_set_mode(struct tegra_dc *dc, const struct tegra_dc_mode *mode)
+{
+ memcpy(&dc->mode, mode, sizeof(dc->mode));
+
+ print_mode(dc, mode, __func__);
+
+ return 0;
+}
+EXPORT_SYMBOL(tegra_dc_set_mode);
+
+int tegra_dc_set_fb_mode(struct tegra_dc *dc,
+ const struct fb_videomode *fbmode, bool stereo_mode)
+{
+ struct tegra_dc_mode mode;
+
+ if (!fbmode->pixclock)
+ return -EINVAL;
+
+ mode.pclk = PICOS2KHZ(fbmode->pixclock) * 1000;
+ mode.h_sync_width = fbmode->hsync_len;
+ mode.v_sync_width = fbmode->vsync_len;
+ mode.h_back_porch = fbmode->left_margin;
+ mode.v_back_porch = fbmode->upper_margin;
+ mode.h_active = fbmode->xres;
+ mode.v_active = fbmode->yres;
+ mode.h_front_porch = fbmode->right_margin;
+ mode.v_front_porch = fbmode->lower_margin;
+ mode.stereo_mode = stereo_mode;
+ if (dc->out->type == TEGRA_DC_OUT_HDMI) {
+ /* HDMI controller requires h_ref=1, v_ref=1 */
+ mode.h_ref_to_sync = 1;
+ mode.v_ref_to_sync = 1;
+ } else {
+ calc_ref_to_sync(&mode);
+ }
+ if (!check_ref_to_sync(&mode)) {
+ dev_err(&dc->ndev->dev,
+ "Display timing doesn't meet restrictions.\n");
+ return -EINVAL;
+ }
+ dev_info(&dc->ndev->dev, "Using mode %dx%d pclk=%d href=%d vref=%d\n",
+ mode.h_active, mode.v_active, mode.pclk,
+ mode.h_ref_to_sync, mode.v_ref_to_sync
+ );
+
+#ifndef CONFIG_TEGRA_HDMI_74MHZ_LIMIT
+ /* Double the pixel clock and update v_active only for
+ * frame packed mode */
+ if (mode.stereo_mode) {
+ mode.pclk *= 2;
+ /* total v_active = yres*2 + activespace */
+ mode.v_active = fbmode->yres * 2 +
+ fbmode->vsync_len +
+ fbmode->upper_margin +
+ fbmode->lower_margin;
+ }
+#endif
+
+ mode.flags = 0;
+
+ if (!(fbmode->sync & FB_SYNC_HOR_HIGH_ACT))
+ mode.flags |= TEGRA_DC_MODE_FLAG_NEG_H_SYNC;
+
+ if (!(fbmode->sync & FB_SYNC_VERT_HIGH_ACT))
+ mode.flags |= TEGRA_DC_MODE_FLAG_NEG_V_SYNC;
+
+ return tegra_dc_set_mode(dc, &mode);
+}
+EXPORT_SYMBOL(tegra_dc_set_fb_mode);
diff --git a/drivers/video/tegra/dc/nvhdcp.c b/drivers/video/tegra/dc/nvhdcp.c
index 263de07a3da0..3566e2bd33b5 100644
--- a/drivers/video/tegra/dc/nvhdcp.c
+++ b/drivers/video/tegra/dc/nvhdcp.c
@@ -1,7 +1,7 @@
/*
* drivers/video/tegra/dc/nvhdcp.c
*
- * Copyright (c) 2010-2011, NVIDIA Corporation.
+ * Copyright (c) 2010-2012, NVIDIA CORPORATION, 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
diff --git a/drivers/video/tegra/dc/nvhdcp.h b/drivers/video/tegra/dc/nvhdcp.h
index 90ea0be36d19..ce4c7f806745 100644
--- a/drivers/video/tegra/dc/nvhdcp.h
+++ b/drivers/video/tegra/dc/nvhdcp.h
@@ -1,7 +1,7 @@
/*
* drivers/video/tegra/dc/nvhdcp.h
*
- * Copyright (c) 2010-2011, NVIDIA Corporation.
+ * Copyright (c) 2010-2012, NVIDIA CORPORATION, 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
diff --git a/drivers/video/tegra/dc/nvsd.c b/drivers/video/tegra/dc/nvsd.c
index 65d518759243..e3058b596f69 100644
--- a/drivers/video/tegra/dc/nvsd.c
+++ b/drivers/video/tegra/dc/nvsd.c
@@ -1,7 +1,7 @@
/*
* drivers/video/tegra/dc/nvsd.c
*
- * Copyright (c) 2010-2012, NVIDIA Corporation.
+ * Copyright (c) 2010-2012, NVIDIA CORPORATION, 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
@@ -378,7 +378,10 @@ void nvsd_init(struct tegra_dc *dc, struct tegra_dc_sd_settings *settings)
val = tegra_dc_readl(dc, DC_DISP_SD_CONTROL);
if (val & SD_ENABLE_NORMAL)
- i = tegra_dc_readl(dc, DC_DISP_SD_HW_K_VALUES);
+ if (settings->phase_in_adjustments)
+ i = tegra_dc_readl(dc, DC_DISP_SD_MAN_K_VALUES);
+ else
+ i = tegra_dc_readl(dc, DC_DISP_SD_HW_K_VALUES);
else
i = 0; /* 0 values for RGB = 1.0, i.e. non-affected */
diff --git a/drivers/video/tegra/dc/nvsd.h b/drivers/video/tegra/dc/nvsd.h
index f7fc4a1ead6e..d6f9dc148320 100644
--- a/drivers/video/tegra/dc/nvsd.h
+++ b/drivers/video/tegra/dc/nvsd.h
@@ -1,7 +1,7 @@
/*
* drivers/video/tegra/dc/nvsd.h
*
- * Copyright (c) 2010-2011, NVIDIA Corporation.
+ * Copyright (c) 2010-2012, NVIDIA CORPORATION, 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
diff --git a/drivers/video/tegra/dc/rgb.c b/drivers/video/tegra/dc/rgb.c
index 6787ec38d38d..b4097d98a9ba 100644
--- a/drivers/video/tegra/dc/rgb.c
+++ b/drivers/video/tegra/dc/rgb.c
@@ -4,6 +4,8 @@
* Copyright (C) 2010 Google, Inc.
* Author: Erik Gilling <konkers@android.com>
*
+ * Copyright (c) 2010-2012, NVIDIA CORPORATION, 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.
@@ -90,7 +92,7 @@ static const u32 tegra_dc_rgb_disable_pintable[] = {
DC_COM_PIN_OUTPUT_SELECT6, 0x00000000,
};
-void tegra_dc_rgb_enable(struct tegra_dc *dc)
+static void tegra_dc_rgb_enable(struct tegra_dc *dc)
{
int i;
u32 out_sel_pintable[ARRAY_SIZE(tegra_dc_rgb_enable_out_sel_pintable)];
@@ -150,7 +152,7 @@ void tegra_dc_rgb_enable(struct tegra_dc *dc)
tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
}
-void tegra_dc_rgb_disable(struct tegra_dc *dc)
+static void tegra_dc_rgb_disable(struct tegra_dc *dc)
{
tegra_dc_writel(dc, 0x00000000, DC_CMD_DISPLAY_POWER_CONTROL);
diff --git a/drivers/video/tegra/dc/window.c b/drivers/video/tegra/dc/window.c
new file mode 100644
index 000000000000..5161dd4f7003
--- /dev/null
+++ b/drivers/video/tegra/dc/window.c
@@ -0,0 +1,466 @@
+/*
+ * drivers/video/tegra/dc/window.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * Copyright (c) 2010-2012, NVIDIA CORPORATION, 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/err.h>
+#include <linux/types.h>
+#include <mach/dc.h>
+
+#include "dc_reg.h"
+#include "dc_config.h"
+#include "dc_priv.h"
+
+static int no_vsync;
+
+module_param_named(no_vsync, no_vsync, int, S_IRUGO | S_IWUSR);
+
+static bool tegra_dc_windows_are_clean(struct tegra_dc_win *windows[],
+ int n)
+{
+ int i;
+
+ for (i = 0; i < n; i++) {
+ if (windows[i]->dirty)
+ return false;
+ }
+
+ return true;
+}
+
+static int get_topmost_window(u32 *depths, unsigned long *wins)
+{
+ int idx, best = -1;
+
+ for_each_set_bit(idx, wins, DC_N_WINDOWS) {
+ if (best == -1 || depths[idx] < depths[best])
+ best = idx;
+ }
+ clear_bit(best, wins);
+ return best;
+}
+
+static u32 blend_topwin(u32 flags)
+{
+ if (flags & TEGRA_WIN_FLAG_BLEND_COVERAGE)
+ return BLEND(NOKEY, ALPHA, 0xff, 0xff);
+ else if (flags & TEGRA_WIN_FLAG_BLEND_PREMULT)
+ return BLEND(NOKEY, PREMULT, 0xff, 0xff);
+ else
+ return BLEND(NOKEY, FIX, 0xff, 0xff);
+}
+
+static u32 blend_2win(int idx, unsigned long behind_mask, u32* flags, int xy)
+{
+ int other;
+
+ for (other = 0; other < DC_N_WINDOWS; other++) {
+ if (other != idx && (xy-- == 0))
+ break;
+ }
+ if (BIT(other) & behind_mask)
+ return blend_topwin(flags[idx]);
+ else if (flags[other])
+ return BLEND(NOKEY, DEPENDANT, 0x00, 0x00);
+ else
+ return BLEND(NOKEY, FIX, 0x00, 0x00);
+}
+
+static u32 blend_3win(int idx, unsigned long behind_mask, u32* flags)
+{
+ unsigned long infront_mask;
+ int first;
+
+ infront_mask = ~(behind_mask | BIT(idx));
+ infront_mask &= (BIT(DC_N_WINDOWS) - 1);
+ first = ffs(infront_mask) - 1;
+
+ if (!infront_mask)
+ return blend_topwin(flags[idx]);
+ else if (behind_mask && first != -1 && flags[first])
+ return BLEND(NOKEY, DEPENDANT, 0x00, 0x00);
+ else
+ return BLEND(NOKEY, FIX, 0x0, 0x0);
+}
+
+static void tegra_dc_set_blending(struct tegra_dc *dc,
+ struct tegra_dc_blend *blend)
+{
+ unsigned long mask = BIT(DC_N_WINDOWS) - 1;
+
+ while (mask) {
+ int idx = get_topmost_window(blend->z, &mask);
+
+ tegra_dc_writel(dc, WINDOW_A_SELECT << idx,
+ DC_CMD_DISPLAY_WINDOW_HEADER);
+ tegra_dc_writel(dc, BLEND(NOKEY, FIX, 0xff, 0xff),
+ DC_WIN_BLEND_NOKEY);
+ tegra_dc_writel(dc, BLEND(NOKEY, FIX, 0xff, 0xff),
+ DC_WIN_BLEND_1WIN);
+ tegra_dc_writel(dc, blend_2win(idx, mask, blend->flags, 0),
+ DC_WIN_BLEND_2WIN_X);
+ tegra_dc_writel(dc, blend_2win(idx, mask, blend->flags, 1),
+ DC_WIN_BLEND_2WIN_Y);
+ tegra_dc_writel(dc, blend_3win(idx, mask, blend->flags),
+ DC_WIN_BLEND_3WIN_XY);
+ }
+}
+
+/* does not support syncing windows on multiple dcs in one call */
+int tegra_dc_sync_windows(struct tegra_dc_win *windows[], int n)
+{
+ int ret;
+ if (n < 1 || n > DC_N_WINDOWS)
+ return -EINVAL;
+
+ if (!windows[0]->dc->enabled)
+ return -EFAULT;
+
+#ifdef CONFIG_TEGRA_SIMULATION_PLATFORM
+ /* Don't want to timeout on simulator */
+ ret = wait_event_interruptible(windows[0]->dc->wq,
+ tegra_dc_windows_are_clean(windows, n));
+#else
+ trace_printk("%s:Before wait_event_interruptible_timeout\n",
+ windows[0]->dc->ndev->name);
+ ret = wait_event_interruptible_timeout(windows[0]->dc->wq,
+ tegra_dc_windows_are_clean(windows, n),
+ HZ);
+ trace_printk("%s:After wait_event_interruptible_timeout\n",
+ windows[0]->dc->ndev->name);
+#endif
+ return ret;
+}
+EXPORT_SYMBOL(tegra_dc_sync_windows);
+
+static inline u32 compute_dda_inc(fixed20_12 in, unsigned out_int,
+ bool v, unsigned Bpp)
+{
+ /*
+ * min(round((prescaled_size_in_pixels - 1) * 0x1000 /
+ * (post_scaled_size_in_pixels - 1)), MAX)
+ * Where the value of MAX is as follows:
+ * For V_DDA_INCREMENT: 15.0 (0xF000)
+ * For H_DDA_INCREMENT: 4.0 (0x4000) for 4 Bytes/pix formats.
+ * 8.0 (0x8000) for 2 Bytes/pix formats.
+ */
+
+ fixed20_12 out = dfixed_init(out_int);
+ u32 dda_inc;
+ int max;
+
+ if (v) {
+ max = 15;
+ } else {
+ switch (Bpp) {
+ default:
+ WARN_ON_ONCE(1);
+ /* fallthrough */
+ case 4:
+ max = 4;
+ break;
+ case 2:
+ max = 8;
+ break;
+ }
+ }
+
+ out.full = max_t(u32, out.full - dfixed_const(1), dfixed_const(1));
+ in.full -= dfixed_const(1);
+
+ dda_inc = dfixed_div(in, out);
+
+ dda_inc = min_t(u32, dda_inc, dfixed_const(max));
+
+ return dda_inc;
+}
+
+static inline u32 compute_initial_dda(fixed20_12 in)
+{
+ return dfixed_frac(in);
+}
+
+/* does not support updating windows on multiple dcs in one call */
+int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
+{
+ struct tegra_dc *dc;
+ unsigned long update_mask = GENERAL_ACT_REQ;
+ unsigned long val;
+ bool update_blend = false;
+ int i;
+
+ dc = windows[0]->dc;
+
+ if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) {
+ /* Acquire one_shot_lock to avoid race condition between
+ * cancellation of old delayed work and schedule of new
+ * delayed work. */
+ mutex_lock(&dc->one_shot_lock);
+ cancel_delayed_work_sync(&dc->one_shot_work);
+ }
+ mutex_lock(&dc->lock);
+
+ if (!dc->enabled) {
+ mutex_unlock(&dc->lock);
+ if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
+ mutex_unlock(&dc->one_shot_lock);
+ return -EFAULT;
+ }
+
+ if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_LP_MODE)
+ tegra_dc_host_resume(dc);
+
+ if (no_vsync)
+ tegra_dc_writel(dc, WRITE_MUX_ACTIVE | READ_MUX_ACTIVE,
+ DC_CMD_STATE_ACCESS);
+ else
+ tegra_dc_writel(dc, WRITE_MUX_ASSEMBLY | READ_MUX_ASSEMBLY,
+ DC_CMD_STATE_ACCESS);
+
+ for (i = 0; i < n; i++) {
+ struct tegra_dc_win *win = windows[i];
+ unsigned h_dda;
+ unsigned v_dda;
+ fixed20_12 h_offset, v_offset;
+ bool invert_h = (win->flags & TEGRA_WIN_FLAG_INVERT_H) != 0;
+ bool invert_v = (win->flags & TEGRA_WIN_FLAG_INVERT_V) != 0;
+ bool yuv = tegra_dc_is_yuv(win->fmt);
+ bool yuvp = tegra_dc_is_yuv_planar(win->fmt);
+ unsigned Bpp = tegra_dc_fmt_bpp(win->fmt) / 8;
+ /* Bytes per pixel of bandwidth, used for dda_inc calculation */
+ unsigned Bpp_bw = Bpp * (yuvp ? 2 : 1);
+ const bool filter_h = win_use_h_filter(dc, win);
+ const bool filter_v = win_use_v_filter(dc, win);
+
+ if (win->z != dc->blend.z[win->idx]) {
+ dc->blend.z[win->idx] = win->z;
+ update_blend = true;
+ }
+ if ((win->flags & TEGRA_WIN_BLEND_FLAGS_MASK) !=
+ dc->blend.flags[win->idx]) {
+ dc->blend.flags[win->idx] =
+ win->flags & TEGRA_WIN_BLEND_FLAGS_MASK;
+ update_blend = true;
+ }
+
+ tegra_dc_writel(dc, WINDOW_A_SELECT << win->idx,
+ DC_CMD_DISPLAY_WINDOW_HEADER);
+
+ if (!no_vsync)
+ update_mask |= WIN_A_ACT_REQ << win->idx;
+
+ if (!WIN_IS_ENABLED(win)) {
+ dc->windows[i].dirty = 1;
+ tegra_dc_writel(dc, 0, DC_WIN_WIN_OPTIONS);
+ continue;
+ }
+
+ tegra_dc_writel(dc, win->fmt & 0x1f, DC_WIN_COLOR_DEPTH);
+ tegra_dc_writel(dc, win->fmt >> 6, DC_WIN_BYTE_SWAP);
+
+ tegra_dc_writel(dc,
+ V_POSITION(win->out_y) | H_POSITION(win->out_x),
+ DC_WIN_POSITION);
+ tegra_dc_writel(dc,
+ V_SIZE(win->out_h) | H_SIZE(win->out_w),
+ DC_WIN_SIZE);
+
+ if (tegra_dc_feature_has_scaling(dc, win->idx)) {
+ tegra_dc_writel(dc,
+ V_PRESCALED_SIZE(dfixed_trunc(win->h)) |
+ H_PRESCALED_SIZE(dfixed_trunc(win->w) * Bpp),
+ DC_WIN_PRESCALED_SIZE);
+
+ h_dda = compute_dda_inc(win->w, win->out_w, false,
+ Bpp_bw);
+ v_dda = compute_dda_inc(win->h, win->out_h, true,
+ Bpp_bw);
+ tegra_dc_writel(dc, V_DDA_INC(v_dda) |
+ H_DDA_INC(h_dda), DC_WIN_DDA_INCREMENT);
+ h_dda = compute_initial_dda(win->x);
+ v_dda = compute_initial_dda(win->y);
+ tegra_dc_writel(dc, h_dda, DC_WIN_H_INITIAL_DDA);
+ tegra_dc_writel(dc, v_dda, DC_WIN_V_INITIAL_DDA);
+ }
+
+ tegra_dc_writel(dc, 0, DC_WIN_BUF_STRIDE);
+ tegra_dc_writel(dc, 0, DC_WIN_UV_BUF_STRIDE);
+ tegra_dc_writel(dc, (unsigned long)win->phys_addr,
+ DC_WINBUF_START_ADDR);
+
+ if (!yuvp) {
+ tegra_dc_writel(dc, win->stride, DC_WIN_LINE_STRIDE);
+ } else {
+ tegra_dc_writel(dc,
+ (unsigned long)win->phys_addr_u,
+ DC_WINBUF_START_ADDR_U);
+ tegra_dc_writel(dc,
+ (unsigned long)win->phys_addr_v,
+ DC_WINBUF_START_ADDR_V);
+ tegra_dc_writel(dc,
+ LINE_STRIDE(win->stride) |
+ UV_LINE_STRIDE(win->stride_uv),
+ DC_WIN_LINE_STRIDE);
+ }
+
+ h_offset = win->x;
+ if (invert_h) {
+ h_offset.full += win->w.full - dfixed_const(1);
+ }
+
+ v_offset = win->y;
+ if (invert_v) {
+ v_offset.full += win->h.full - dfixed_const(1);
+ }
+
+ tegra_dc_writel(dc, dfixed_trunc(h_offset) * Bpp,
+ DC_WINBUF_ADDR_H_OFFSET);
+ tegra_dc_writel(dc, dfixed_trunc(v_offset),
+ DC_WINBUF_ADDR_V_OFFSET);
+
+ if (tegra_dc_feature_has_tiling(dc, win->idx)) {
+ if (WIN_IS_TILED(win))
+ tegra_dc_writel(dc,
+ DC_WIN_BUFFER_ADDR_MODE_TILE |
+ DC_WIN_BUFFER_ADDR_MODE_TILE_UV,
+ DC_WIN_BUFFER_ADDR_MODE);
+ else
+ tegra_dc_writel(dc,
+ DC_WIN_BUFFER_ADDR_MODE_LINEAR |
+ DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV,
+ DC_WIN_BUFFER_ADDR_MODE);
+ }
+
+ val = WIN_ENABLE;
+ if (yuv)
+ val |= CSC_ENABLE;
+ else if (tegra_dc_fmt_bpp(win->fmt) < 24)
+ val |= COLOR_EXPAND;
+
+ if (win->ppflags & TEGRA_WIN_PPFLAG_CP_ENABLE)
+ val |= CP_ENABLE;
+
+ if (filter_h)
+ val |= H_FILTER_ENABLE;
+ if (filter_v)
+ val |= V_FILTER_ENABLE;
+
+ if (invert_h)
+ val |= H_DIRECTION_DECREMENT;
+ if (invert_v)
+ val |= V_DIRECTION_DECREMENT;
+
+ tegra_dc_writel(dc, val, DC_WIN_WIN_OPTIONS);
+
+#ifdef CONFIG_ARCH_TEGRA_3x_SOC
+ if (win->global_alpha == 255)
+ tegra_dc_writel(dc, 0, DC_WIN_GLOBAL_ALPHA);
+ else
+ tegra_dc_writel(dc, GLOBAL_ALPHA_ENABLE |
+ win->global_alpha, DC_WIN_GLOBAL_ALPHA);
+#endif
+
+ win->dirty = no_vsync ? 0 : 1;
+
+ dev_dbg(&dc->ndev->dev, "%s():idx=%d z=%d x=%d y=%d w=%d h=%d "
+ "out_x=%u out_y=%u out_w=%u out_h=%u "
+ "fmt=%d yuvp=%d Bpp=%u filter_h=%d filter_v=%d",
+ __func__, win->idx, win->z,
+ dfixed_trunc(win->x), dfixed_trunc(win->y),
+ dfixed_trunc(win->w), dfixed_trunc(win->h),
+ win->out_x, win->out_y, win->out_w, win->out_h,
+ win->fmt, yuvp, Bpp, filter_h, filter_v);
+ trace_printk("%s:win%u in:%ux%u out:%ux%u fmt=%d\n",
+ dc->ndev->name, win->idx, dfixed_trunc(win->w),
+ dfixed_trunc(win->h), win->out_w, win->out_h, win->fmt);
+ }
+
+ if (update_blend) {
+ tegra_dc_set_blending(dc, &dc->blend);
+ for (i = 0; i < DC_N_WINDOWS; i++) {
+ if (!no_vsync)
+ dc->windows[i].dirty = 1;
+ update_mask |= WIN_A_ACT_REQ << i;
+ }
+ }
+
+ tegra_dc_set_dynamic_emc(windows, n);
+
+ tegra_dc_writel(dc, update_mask << 8, DC_CMD_STATE_CONTROL);
+
+ tegra_dc_writel(dc, FRAME_END_INT | V_BLANK_INT, DC_CMD_INT_STATUS);
+ if (!no_vsync) {
+ set_bit(V_BLANK_FLIP, &dc->vblank_ref_count);
+ tegra_dc_unmask_interrupt(dc,
+ FRAME_END_INT | V_BLANK_INT | ALL_UF_INT);
+ } else {
+ clear_bit(V_BLANK_FLIP, &dc->vblank_ref_count);
+ tegra_dc_mask_interrupt(dc,
+ FRAME_END_INT | V_BLANK_INT | ALL_UF_INT);
+ }
+
+ if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
+ schedule_delayed_work(&dc->one_shot_work,
+ msecs_to_jiffies(dc->one_shot_delay_ms));
+
+ /* update EMC clock if calculated bandwidth has changed */
+ tegra_dc_program_bandwidth(dc, false);
+
+ if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
+ update_mask |= NC_HOST_TRIG;
+
+ tegra_dc_writel(dc, update_mask, DC_CMD_STATE_CONTROL);
+ trace_printk("%s:update_mask=%#lx\n", dc->ndev->name, update_mask);
+
+ mutex_unlock(&dc->lock);
+ if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
+ mutex_unlock(&dc->one_shot_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(tegra_dc_update_windows);
+
+void tegra_dc_trigger_windows(struct tegra_dc *dc)
+{
+ u32 val, i;
+ u32 completed = 0;
+ u32 dirty = 0;
+
+ val = tegra_dc_readl(dc, DC_CMD_STATE_CONTROL);
+ for (i = 0; i < DC_N_WINDOWS; i++) {
+#ifdef CONFIG_TEGRA_SIMULATION_PLATFORM
+ /* FIXME: this is not needed when the simulator
+ clears WIN_x_UPDATE bits as in HW */
+ dc->windows[i].dirty = 0;
+ completed = 1;
+#else
+ if (!(val & (WIN_A_ACT_REQ << i))) {
+ dc->windows[i].dirty = 0;
+ completed = 1;
+ } else {
+ dirty = 1;
+ }
+#endif
+ }
+
+ if (!dirty) {
+ if (!(dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE))
+ tegra_dc_mask_interrupt(dc, FRAME_END_INT);
+ }
+
+ if (completed)
+ wake_up(&dc->wq);
+}
+
diff --git a/drivers/video/tegra/fb.c b/drivers/video/tegra/fb.c
index fc9befdf72c8..cb7525e049e9 100644
--- a/drivers/video/tegra/fb.c
+++ b/drivers/video/tegra/fb.c
@@ -6,7 +6,7 @@
* Colin Cross <ccross@android.com>
* Travis Geiselbrecht <travis@palm.com>
*
- * Copyright (C) 2010-2011 NVIDIA Corporation
+ * Copyright (c) 2010-2012, NVIDIA CORPORATION, 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
@@ -37,14 +37,16 @@
#include <mach/dc.h>
#include <mach/fb.h>
#include <linux/nvhost.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
+#include <linux/console.h>
+
#include "host/dev.h"
#include "nvmap/nvmap.h"
#include "dc/dc_priv.h"
/* Pad pitch to 16-byte boundary. */
-#define TEGRA_LINEAR_PITCH_ALIGNMENT 16
+#define TEGRA_LINEAR_PITCH_ALIGNMENT 32
struct tegra_fb_info {
struct tegra_dc_win *win;
@@ -155,8 +157,10 @@ static int tegra_fb_set_par(struct fb_info *info)
#else
FB_VMODE_STEREO_LEFT_RIGHT);
#endif
-
tegra_dc_set_fb_mode(tegra_fb->win->dc, info->mode, stereo);
+ /* Reflect the mode change on dc */
+ tegra_dc_disable(tegra_fb->win->dc);
+ tegra_dc_enable(tegra_fb->win->dc);
tegra_fb->win->w.full = dfixed_const(info->mode->xres);
tegra_fb->win->h.full = dfixed_const(info->mode->yres);
@@ -245,51 +249,6 @@ static int tegra_fb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
return 0;
}
-#if defined(CONFIG_FRAMEBUFFER_CONSOLE)
-static void tegra_fb_flip_win(struct tegra_fb_info *tegra_fb)
-{
- struct tegra_dc_win *win = tegra_fb->win;
- struct fb_info *info = tegra_fb->info;
-
- win->x.full = dfixed_const(0);
- win->y.full = dfixed_const(0);
- win->w.full = dfixed_const(tegra_fb->xres);
- win->h.full = dfixed_const(tegra_fb->yres);
-
- /* TODO: set to output res dc */
- win->out_x = 0;
- win->out_y = 0;
- win->out_w = tegra_fb->xres;
- win->out_h = tegra_fb->yres;
- win->z = 0;
- win->phys_addr = info->fix.smem_start +
- (info->var.yoffset * info->fix.line_length) +
- (info->var.xoffset * (info->var.bits_per_pixel / 8));
- win->virt_addr = info->screen_base;
-
- win->phys_addr_u = 0;
- win->phys_addr_v = 0;
- win->stride = info->fix.line_length;
- win->stride_uv = 0;
-
- switch (info->var.bits_per_pixel) {
- default:
- WARN_ON(1);
- /* fall through */
- case 32:
- tegra_fb->win->fmt = TEGRA_WIN_FMT_R8G8B8A8;
- break;
- case 16:
- tegra_fb->win->fmt = TEGRA_WIN_FMT_B5G6R5;
- break;
- }
- win->flags = TEGRA_WIN_FLAG_ENABLED;
-
- tegra_dc_update_windows(&tegra_fb->win, 1);
- tegra_dc_sync_windows(&tegra_fb->win, 1);
-}
-#endif
-
static int tegra_fb_blank(int blank, struct fb_info *info)
{
struct tegra_fb_info *tegra_fb = info->par;
@@ -466,13 +425,63 @@ static struct fb_ops tegra_fb_ops = {
.fb_ioctl = tegra_fb_ioctl,
};
+const struct fb_videomode *tegra_fb_find_best_mode(
+ struct fb_var_screeninfo *var,
+ struct list_head *head)
+{
+ struct list_head *pos;
+ struct fb_modelist *modelist;
+ struct fb_videomode *mode, *best = NULL;
+ int diff = 0;
+
+ list_for_each(pos, head) {
+ int d;
+
+ modelist = list_entry(pos, struct fb_modelist, list);
+ mode = &modelist->mode;
+
+ if (mode->xres >= var->xres && mode->yres >= var->yres) {
+ d = (mode->xres - var->xres) +
+ (mode->yres - var->yres);
+ if (diff < d) {
+ diff = d;
+ best = mode;
+ } else if (diff == d && best &&
+ mode->refresh > best->refresh)
+ best = mode;
+ }
+ }
+ return best;
+}
+
+static int tegra_fb_activate_mode(struct tegra_fb_info *fb_info,
+ struct fb_var_screeninfo *var)
+{
+ int err;
+ struct fb_info *info = fb_info->info;
+
+ var->activate |= FB_ACTIVATE_FORCE;
+ console_lock();
+ info->flags |= FBINFO_MISC_USEREVENT;
+ err = fb_set_var(info, var);
+ info->flags &= ~FBINFO_MISC_USEREVENT;
+ console_unlock();
+ if (err)
+ return err;
+ return 0;
+}
+
void tegra_fb_update_monspecs(struct tegra_fb_info *fb_info,
struct fb_monspecs *specs,
bool (*mode_filter)(const struct tegra_dc *dc,
struct fb_videomode *mode))
{
- struct fb_event event;
int i;
+ int ret = 0;
+ struct fb_event event;
+ struct fb_info *info = fb_info->info;
+ const struct fb_videomode *best_mode = NULL;
+ struct fb_var_screeninfo var = {0,};
mutex_lock(&fb_info->info->lock);
fb_destroy_modedb(fb_info->info->monspecs.modedb);
@@ -499,19 +508,56 @@ void tegra_fb_update_monspecs(struct tegra_fb_info *fb_info,
sizeof(fb_info->info->monspecs));
fb_info->info->mode = specs->modedb;
+ /* Prepare a mode db */
for (i = 0; i < specs->modedb_len; i++) {
- if (mode_filter) {
- if (mode_filter(fb_info->win->dc, &specs->modedb[i]))
- fb_add_videomode(&specs->modedb[i],
+ if (info->fbops->fb_check_var) {
+ struct fb_videomode m;
+
+ /* Call mode filter to check mode */
+ fb_videomode_to_var(&var, &specs->modedb[i]);
+ if (!(info->fbops->fb_check_var(&var, info))) {
+ fb_var_to_videomode(&m, &var);
+ fb_add_videomode(&m,
&fb_info->info->modelist);
+ }
} else {
fb_add_videomode(&specs->modedb[i],
&fb_info->info->modelist);
}
}
+ /* Get the best mode from modedb and apply on fb */
+ var.xres = 0;
+ var.yres = 0;
+ best_mode = tegra_fb_find_best_mode(&var, &info->modelist);
+
+ /* Update framebuffer with best mode */
+ fb_videomode_to_var(&var, best_mode);
+
+ /* TODO: Get proper way of getting rid of a 0 bpp */
+ if (!var.bits_per_pixel)
+ var.bits_per_pixel = 32;
+
+ memcpy(&info->var, &var, sizeof(struct fb_var_screeninfo));
+
+ ret = tegra_fb_activate_mode(fb_info, &var);
+ if (ret)
+ return;
+
event.info = fb_info->info;
+
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE
+/* Lock the console before sending the noti. Fbconsole
+ * on HDMI might be using console
+ */
+ console_lock();
+#endif
fb_notifier_call_chain(FB_EVENT_NEW_MODELIST, &event);
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE
+/* Unlock the console */
+ console_unlock();
+#endif
+
mutex_unlock(&fb_info->info->lock);
}
@@ -527,6 +573,7 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev,
unsigned long fb_size = 0;
unsigned long fb_phys = 0;
int ret = 0;
+ unsigned stride;
win = tegra_dc_get_window(dc, fb_data->win);
if (!win) {
@@ -560,6 +607,11 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev,
tegra_fb->valid = true;
}
+ stride = tegra_dc_get_stride(dc, 0);
+ if (!stride) /* default to pad the stride to 16-byte boundary. */
+ stride = round_up(info->fix.line_length,
+ TEGRA_LINEAR_PITCH_ALIGNMENT);
+
info->fbops = &tegra_fb_ops;
info->pseudo_palette = pseudo_palette;
info->screen_base = fb_base;
@@ -574,9 +626,7 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev,
info->fix.smem_start = fb_phys;
info->fix.smem_len = fb_size;
info->fix.line_length = fb_data->xres * fb_data->bits_per_pixel / 8;
- /* Pad the stride to 16-byte boundary. */
- info->fix.line_length = round_up(info->fix.line_length,
- TEGRA_LINEAR_PITCH_ALIGNMENT);
+ info->fix.line_length = stride;
info->var.xres = fb_data->xres;
info->var.yres = fb_data->yres;
diff --git a/drivers/video/tegra/host/Makefile b/drivers/video/tegra/host/Makefile
index 0180885af4d7..6e5e469897b3 100644
--- a/drivers/video/tegra/host/Makefile
+++ b/drivers/video/tegra/host/Makefile
@@ -1,4 +1,6 @@
GCOV_PROFILE := y
+EXTRA_CFLAGS += -Idrivers/video/tegra/host
+
nvhost-objs = \
nvhost_acm.o \
nvhost_syncpt.o \
@@ -9,15 +11,18 @@ nvhost-objs = \
bus.o \
dev.o \
debug.o \
- bus_client.o
+ bus_client.o \
+ chip_support.o \
+ nvhost_memmgr.o
obj-$(CONFIG_TEGRA_GRHOST) += mpe/
obj-$(CONFIG_TEGRA_GRHOST) += gr3d/
obj-$(CONFIG_TEGRA_GRHOST) += host1x/
obj-$(CONFIG_TEGRA_GRHOST) += t20/
obj-$(CONFIG_TEGRA_GRHOST) += t30/
-obj-$(CONFIG_TEGRA_GRHOST) += dsi/
obj-$(CONFIG_TEGRA_GRHOST) += gr2d/
obj-$(CONFIG_TEGRA_GRHOST) += isp/
obj-$(CONFIG_TEGRA_GRHOST) += vi/
obj-$(CONFIG_TEGRA_GRHOST) += nvhost.o
+
+obj-$(CONFIG_TEGRA_GRHOST_USE_NVMAP) += nvmap.o
diff --git a/drivers/video/tegra/host/bus.c b/drivers/video/tegra/host/bus.c
index 774aac7bd431..758a5ca4ad94 100644
--- a/drivers/video/tegra/host/bus.c
+++ b/drivers/video/tegra/host/bus.c
@@ -17,11 +17,14 @@
*
*/
+#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/nvhost.h>
+#include "bus.h"
#include "dev.h"
+struct nvhost_bus *nvhost_bus_inst;
struct nvhost_master *nvhost;
struct resource *nvhost_get_resource(struct nvhost_device *dev,
@@ -72,12 +75,43 @@ int nvhost_get_irq_byname(struct nvhost_device *dev, const char *name)
}
EXPORT_SYMBOL_GPL(nvhost_get_irq_byname);
+static struct nvhost_device_id *nvhost_bus_match_id(struct nvhost_device *dev,
+ struct nvhost_device_id *id_table)
+{
+ while (id_table->name[0]) {
+ if (strcmp(dev->name, id_table->name) == 0
+ && dev->version == id_table->version)
+ return id_table;
+ id_table++;
+ }
+ return NULL;
+}
+
+static int nvhost_bus_match(struct device *_dev, struct device_driver *drv)
+{
+ struct nvhost_device *dev = to_nvhost_device(_dev);
+ struct nvhost_driver *ndrv = to_nvhost_driver(drv);
+
+ /* check if driver support multiple devices through id_table */
+ if (ndrv->id_table)
+ return nvhost_bus_match_id(dev, ndrv->id_table) != NULL;
+ else /* driver does not support id_table */
+ return !strncmp(dev->name, drv->name, strlen(drv->name));
+}
+
static int nvhost_drv_probe(struct device *_dev)
{
struct nvhost_driver *drv = to_nvhost_driver(_dev->driver);
struct nvhost_device *dev = to_nvhost_device(_dev);
- return drv->probe(dev);
+ if (drv && drv->probe) {
+ if (drv->id_table)
+ return drv->probe(dev, nvhost_bus_match_id(dev, drv->id_table));
+ else
+ return drv->probe(dev, NULL);
+ }
+ else
+ return -ENODEV;
}
static int nvhost_drv_remove(struct device *_dev)
@@ -98,7 +132,7 @@ static void nvhost_drv_shutdown(struct device *_dev)
int nvhost_driver_register(struct nvhost_driver *drv)
{
- drv->driver.bus = &nvhost_bus_type;
+ drv->driver.bus = &nvhost_bus_inst->nvhost_bus_type;
if (drv->probe)
drv->driver.probe = nvhost_drv_probe;
if (drv->remove)
@@ -116,6 +150,23 @@ void nvhost_driver_unregister(struct nvhost_driver *drv)
}
EXPORT_SYMBOL_GPL(nvhost_driver_unregister);
+int nvhost_add_devices(struct nvhost_device **devs, int num)
+{
+ int i, ret = 0;
+
+ for (i = 0; i < num; i++) {
+ ret = nvhost_device_register(devs[i]);
+ if (ret) {
+ while (--i >= 0)
+ nvhost_device_unregister(devs[i]);
+ break;
+ }
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(nvhost_add_devices);
+
int nvhost_device_register(struct nvhost_device *dev)
{
int i, ret = 0;
@@ -129,7 +180,7 @@ int nvhost_device_register(struct nvhost_device *dev)
if (!dev->dev.parent && nvhost && nvhost->dev != dev)
dev->dev.parent = &nvhost->dev->dev;
- dev->dev.bus = &nvhost_bus_type;
+ dev->dev.bus = &nvhost_bus_inst->nvhost_bus_type;
if (dev->id != -1)
dev_set_name(&dev->dev, "%s.%d", dev->name, dev->id);
@@ -194,13 +245,6 @@ void nvhost_device_unregister(struct nvhost_device *dev)
}
EXPORT_SYMBOL_GPL(nvhost_device_unregister);
-static int nvhost_bus_match(struct device *_dev, struct device_driver *drv)
-{
- struct nvhost_device *dev = to_nvhost_device(_dev);
-
- return !strncmp(dev->name, drv->name, strlen(drv->name));
-}
-
#ifdef CONFIG_PM_SLEEP
static int nvhost_legacy_suspend(struct device *dev, pm_message_t mesg)
@@ -528,13 +572,6 @@ static const struct dev_pm_ops nvhost_dev_pm_ops = {
.runtime_idle = nvhost_pm_runtime_idle,
};
-struct bus_type nvhost_bus_type = {
- .name = "nvhost",
- .match = nvhost_bus_match,
- .pm = &nvhost_dev_pm_ops,
-};
-EXPORT_SYMBOL(nvhost_bus_type);
-
static int set_parent(struct device *dev, void *data)
{
struct nvhost_device *ndev = to_nvhost_device(dev);
@@ -549,21 +586,44 @@ int nvhost_bus_add_host(struct nvhost_master *host)
nvhost = host;
/* Assign host1x as parent to all devices in nvhost bus */
- bus_for_each_dev(&nvhost_bus_type, NULL, host, set_parent);
+ bus_for_each_dev(&nvhost_bus_inst->nvhost_bus_type, NULL, host, set_parent);
return 0;
}
+struct nvhost_bus *nvhost_bus_get(void)
+{
+ return nvhost_bus_inst;
+}
int nvhost_bus_init(void)
{
int err;
+ struct nvhost_chip_support *chip_ops;
pr_info("host1x bus init\n");
- err = bus_register(&nvhost_bus_type);
+ nvhost_bus_inst = kzalloc(sizeof(*nvhost_bus_inst), GFP_KERNEL);
+ if (nvhost_bus_inst == NULL) {
+ pr_err("%s: Cannot allocate nvhost_bus\n", __func__);
+ return -ENOMEM;
+ }
+
+ chip_ops = kzalloc(sizeof(*chip_ops), GFP_KERNEL);
+ if (chip_ops == NULL) {
+ pr_err("%s: Cannot allocate nvhost_chip_support\n", __func__);
+ kfree(nvhost_bus_inst);
+ nvhost_bus_inst = NULL;
+ return -ENOMEM;
+ }
+
+ nvhost_bus_inst->nvhost_bus_type.name = "nvhost";
+ nvhost_bus_inst->nvhost_bus_type.match = nvhost_bus_match;
+ nvhost_bus_inst->nvhost_bus_type.pm = &nvhost_dev_pm_ops;
+ nvhost_bus_inst->nvhost_chip_ops = chip_ops;
+
+ err = bus_register(&nvhost_bus_inst->nvhost_bus_type);
return err;
}
postcore_initcall(nvhost_bus_init);
-
diff --git a/drivers/video/tegra/host/bus.h b/drivers/video/tegra/host/bus.h
new file mode 100644
index 000000000000..99f820335d60
--- /dev/null
+++ b/drivers/video/tegra/host/bus.h
@@ -0,0 +1,38 @@
+/*
+ * drivers/video/tegra/host/bus.h
+ *
+ * Tegra Graphics Host bus API header
+ *
+ * Copyright (c) 2010-2012, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __NVHOST_BUS_H
+#define __NVHOST_BUS_H
+
+#include <linux/types.h>
+#include <linux/device.h>
+
+#include "chip_support.h"
+
+struct nvhost_bus {
+ struct nvhost_chip_support *nvhost_chip_ops;
+ struct bus_type nvhost_bus_type;
+};
+
+struct nvhost_bus *nvhost_bus_get(void);
+
+extern struct nvhost_bus *nvhost_bus_inst;
+
+#endif
diff --git a/drivers/video/tegra/host/bus_client.c b/drivers/video/tegra/host/bus_client.c
index b49c26e04f29..0137793b39ee 100644
--- a/drivers/video/tegra/host/bus_client.c
+++ b/drivers/video/tegra/host/bus_client.c
@@ -36,7 +36,6 @@
#include <linux/nvhost.h>
#include <linux/nvhost_ioctl.h>
-#include <mach/nvmap.h>
#include <mach/gpufuse.h>
#include <mach/hardware.h>
#include <mach/iomap.h>
@@ -44,11 +43,36 @@
#include "debug.h"
#include "bus_client.h"
#include "dev.h"
+#include "nvhost_memmgr.h"
+#include "chip_support.h"
+#include "nvhost_acm.h"
-void nvhost_read_module_regs(struct nvhost_device *ndev,
+#include "nvhost_channel.h"
+#include "nvhost_job.h"
+#include "nvhost_hwctx.h"
+
+static int validate_reg(struct nvhost_device *ndev, u32 offset, int count)
+{
+ struct resource *r = nvhost_get_resource(ndev, IORESOURCE_MEM, 0);
+ int err = 0;
+
+ if (offset + 4 * count > resource_size(r)
+ || (offset + 4 * count < offset))
+ err = -EPERM;
+
+ return err;
+}
+
+int nvhost_read_module_regs(struct nvhost_device *ndev,
u32 offset, int count, u32 *values)
{
void __iomem *p = ndev->aperture + offset;
+ int err;
+
+ /* verify offset */
+ err = validate_reg(ndev, offset, count);
+ if (err)
+ return err;
nvhost_module_busy(ndev);
while (count--) {
@@ -57,12 +81,20 @@ void nvhost_read_module_regs(struct nvhost_device *ndev,
}
rmb();
nvhost_module_idle(ndev);
+
+ return 0;
}
-void nvhost_write_module_regs(struct nvhost_device *ndev,
+int nvhost_write_module_regs(struct nvhost_device *ndev,
u32 offset, int count, const u32 *values)
{
void __iomem *p = ndev->aperture + offset;
+ int err;
+
+ /* verify offset */
+ err = validate_reg(ndev, offset, count);
+ if (err)
+ return err;
nvhost_module_busy(ndev);
while (count--) {
@@ -71,6 +103,8 @@ void nvhost_write_module_regs(struct nvhost_device *ndev,
}
wmb();
nvhost_module_idle(ndev);
+
+ return 0;
}
struct nvhost_channel_userctx {
@@ -79,51 +113,12 @@ struct nvhost_channel_userctx {
struct nvhost_submit_hdr_ext hdr;
int num_relocshifts;
struct nvhost_job *job;
- struct nvmap_client *nvmap;
+ struct mem_mgr *memmgr;
u32 timeout;
u32 priority;
int clientid;
};
-/*
- * Write cmdbuf to ftrace output. Checks if cmdbuf contents should be output
- * and mmaps the cmdbuf contents if required.
- */
-static void trace_write_cmdbufs(struct nvhost_job *job)
-{
- struct nvmap_handle_ref handle;
- void *mem = NULL;
- int i = 0;
-
- for (i = 0; i < job->num_gathers; i++) {
- struct nvhost_channel_gather *gather = &job->gathers[i];
- if (nvhost_debug_trace_cmdbuf) {
- handle.handle = nvmap_id_to_handle(gather->mem_id);
- mem = nvmap_mmap(&handle);
- if (IS_ERR_OR_NULL(mem))
- mem = NULL;
- };
-
- if (mem) {
- u32 i;
- /*
- * Write in batches of 128 as there seems to be a limit
- * of how much you can output to ftrace at once.
- */
- for (i = 0; i < gather->words; i += TRACE_MAX_LENGTH) {
- trace_nvhost_channel_write_cmdbuf_data(
- job->ch->dev->name,
- gather->mem_id,
- min(gather->words - i,
- TRACE_MAX_LENGTH),
- gather->offset + i * sizeof(u32),
- mem);
- }
- nvmap_munmap(&handle, mem);
- }
- }
-}
-
static int nvhost_channelrelease(struct inode *inode, struct file *filp)
{
struct nvhost_channel_userctx *priv = filp->private_data;
@@ -141,7 +136,7 @@ static int nvhost_channelrelease(struct inode *inode, struct file *filp)
if (priv->job)
nvhost_job_put(priv->job);
- nvmap_client_put(priv->nvmap);
+ mem_op().put_mgr(priv->memmgr);
kfree(priv);
return 0;
}
@@ -174,11 +169,7 @@ static int nvhost_channelopen(struct inode *inode, struct file *filp)
priv->priority = NVHOST_PRIORITY_MEDIUM;
priv->clientid = atomic_add_return(1,
&nvhost_get_host(ch->dev)->clientid);
-
- priv->job = nvhost_job_alloc(ch, priv->hwctx, &priv->hdr,
- NULL, priv->priority, priv->clientid);
- if (!priv->job)
- goto fail;
+ priv->timeout = CONFIG_TEGRA_GRHOST_DEFAULT_TIMEOUT;
return 0;
fail:
@@ -188,21 +179,24 @@ fail:
static int set_submit(struct nvhost_channel_userctx *ctx)
{
- struct device *device = &ctx->ch->dev->dev;
+ struct nvhost_device *ndev = ctx->ch->dev;
+ struct nvhost_master *host = nvhost_get_host(ndev);
/* submit should have at least 1 cmdbuf */
- if (!ctx->hdr.num_cmdbufs)
+ if (!ctx->hdr.num_cmdbufs ||
+ !nvhost_syncpt_is_valid(&host->syncpt,
+ ctx->hdr.syncpt_id))
return -EIO;
- if (!ctx->nvmap) {
- dev_err(device, "no nvmap context set\n");
+ if (!ctx->memmgr) {
+ dev_err(&ndev->dev, "no nvmap context set\n");
return -EFAULT;
}
- ctx->job = nvhost_job_realloc(ctx->job,
+ ctx->job = nvhost_job_alloc(ctx->ch,
ctx->hwctx,
&ctx->hdr,
- ctx->nvmap,
+ ctx->memmgr,
ctx->priority,
ctx->clientid);
if (!ctx->job)
@@ -221,6 +215,11 @@ static void reset_submit(struct nvhost_channel_userctx *ctx)
ctx->hdr.num_relocs = 0;
ctx->num_relocshifts = 0;
ctx->hdr.num_waitchks = 0;
+
+ if (ctx->job) {
+ nvhost_job_put(ctx->job);
+ ctx->job = NULL;
+ }
}
static ssize_t nvhost_channelwrite(struct file *filp, const char __user *buf,
@@ -271,17 +270,28 @@ static ssize_t nvhost_channelwrite(struct file *filp, const char __user *buf,
cmdbuf.mem, cmdbuf.words, cmdbuf.offset);
hdr->num_cmdbufs--;
} else if (hdr->num_relocs) {
- consumed = sizeof(struct nvhost_reloc);
- if (remaining < consumed)
+ int numrelocs = remaining / sizeof(struct nvhost_reloc);
+ if (!numrelocs)
break;
- if (copy_from_user(&job->pinarray[job->num_pins],
+ numrelocs = min_t(int, numrelocs, priv->hdr.num_relocs);
+ consumed = numrelocs * sizeof(struct nvhost_reloc);
+ if (copy_from_user(&job->relocarray[job->num_relocs],
buf, consumed)) {
err = -EFAULT;
break;
}
- trace_nvhost_channel_write_reloc(chname);
- job->num_pins++;
- hdr->num_relocs--;
+ while (numrelocs) {
+ struct nvhost_reloc *reloc =
+ &job->relocarray[job->num_relocs];
+ trace_nvhost_channel_write_reloc(chname,
+ reloc->cmdbuf_mem,
+ reloc->cmdbuf_offset,
+ reloc->target,
+ reloc->target_offset);
+ job->num_relocs++;
+ hdr->num_relocs--;
+ numrelocs--;
+ }
} else if (hdr->num_waitchks) {
int numwaitchks =
(remaining / sizeof(struct nvhost_waitchk));
@@ -302,17 +312,19 @@ static ssize_t nvhost_channelwrite(struct file *filp, const char __user *buf,
hdr->num_waitchks -= numwaitchks;
} else if (priv->num_relocshifts) {
int next_shift =
- job->num_pins - priv->num_relocshifts;
- consumed = sizeof(struct nvhost_reloc_shift);
- if (remaining < consumed)
+ job->num_relocs - priv->num_relocshifts;
+ int num =
+ (remaining / sizeof(struct nvhost_reloc_shift));
+ if (!num)
break;
- if (copy_from_user(
- &job->pinarray[next_shift].reloc_shift,
+ num = min_t(int, num, priv->num_relocshifts);
+ consumed = num * sizeof(struct nvhost_reloc_shift);
+ if (copy_from_user(&job->relocshiftarray[next_shift],
buf, consumed)) {
err = -EFAULT;
break;
}
- priv->num_relocshifts--;
+ priv->num_relocshifts -= num;
} else {
err = -EFAULT;
break;
@@ -335,7 +347,7 @@ static int nvhost_ioctl_channel_flush(
struct nvhost_get_param_args *args,
int null_kickoff)
{
- struct device *device = &ctx->ch->dev->dev;
+ struct nvhost_device *ndev = to_nvhost_device(&ctx->ch->dev->dev);
int err;
trace_nvhost_ioctl_channel_flush(ctx->ch->dev->name);
@@ -345,13 +357,13 @@ static int nvhost_ioctl_channel_flush(
ctx->hdr.num_cmdbufs ||
ctx->hdr.num_waitchks) {
reset_submit(ctx);
- dev_err(device, "channel submit out of sync\n");
+ dev_err(&ndev->dev, "channel submit out of sync\n");
return -EFAULT;
}
- err = nvhost_job_pin(ctx->job);
+ err = nvhost_job_pin(ctx->job, &nvhost_get_host(ndev)->syncpt);
if (err) {
- dev_warn(device, "nvhost_job_pin failed: %d\n", err);
+ dev_warn(&ndev->dev, "nvhost_job_pin failed: %d\n", err);
return err;
}
@@ -364,23 +376,23 @@ static int nvhost_ioctl_channel_flush(
ctx->timeout = nvhost_debug_force_timeout_val;
}
- trace_write_cmdbufs(ctx->job);
-
/* context switch if needed, and submit user's gathers to the channel */
err = nvhost_channel_submit(ctx->job);
args->value = ctx->job->syncpt_end;
if (err)
nvhost_job_unpin(ctx->job);
+ nvhost_job_put(ctx->job);
+ ctx->job = NULL;
+
return err;
}
-static int nvhost_ioctl_channel_read_3d_reg(
- struct nvhost_channel_userctx *ctx,
+static int nvhost_ioctl_channel_read_3d_reg(struct nvhost_channel_userctx *ctx,
struct nvhost_read_3d_reg_args *args)
{
- BUG_ON(!channel_op(ctx->ch).read3dreg);
- return channel_op(ctx->ch).read3dreg(ctx->ch, ctx->hwctx,
+ BUG_ON(!channel_op().read3dreg);
+ return channel_op().read3dreg(ctx->ch, ctx->hwctx,
args->offset, &args->value);
}
@@ -393,11 +405,10 @@ static long nvhost_channelctl(struct file *filp,
if ((_IOC_TYPE(cmd) != NVHOST_IOCTL_MAGIC) ||
(_IOC_NR(cmd) == 0) ||
- (_IOC_NR(cmd) > NVHOST_IOCTL_CHANNEL_LAST))
+ (_IOC_NR(cmd) > NVHOST_IOCTL_CHANNEL_LAST) ||
+ (_IOC_SIZE(cmd) > NVHOST_IOCTL_CHANNEL_MAX_ARG_SIZE))
return -EFAULT;
- BUG_ON(_IOC_SIZE(cmd) > NVHOST_IOCTL_CHANNEL_MAX_ARG_SIZE);
-
if (_IOC_DIR(cmd) & _IOC_WRITE) {
if (copy_from_user(buf, (void __user *)arg, _IOC_SIZE(cmd)))
return -EFAULT;
@@ -460,17 +471,17 @@ static long nvhost_channelctl(struct file *filp,
case NVHOST_IOCTL_CHANNEL_SET_NVMAP_FD:
{
int fd = (int)((struct nvhost_set_nvmap_fd_args *)buf)->fd;
- struct nvmap_client *new_client = nvmap_client_get_file(fd);
+ struct mem_mgr *new_client = mem_op().get_mgr_file(fd);
if (IS_ERR(new_client)) {
err = PTR_ERR(new_client);
break;
}
- if (priv->nvmap)
- nvmap_client_put(priv->nvmap);
+ if (priv->memmgr)
+ mem_op().put_mgr(priv->memmgr);
- priv->nvmap = new_client;
+ priv->memmgr = new_client;
break;
}
case NVHOST_IOCTL_CHANNEL_READ_3D_REG:
@@ -535,18 +546,23 @@ int nvhost_client_user_init(struct nvhost_device *dev)
int err, devno;
struct nvhost_channel *ch = dev->channel;
+ err = alloc_chrdev_region(&devno, 0, 1, IFACE_NAME);
+ if (err < 0) {
+ dev_err(&dev->dev, "failed to allocate devno\n");
+ goto fail;
+ }
cdev_init(&ch->cdev, &nvhost_channelops);
ch->cdev.owner = THIS_MODULE;
- devno = MKDEV(nvhost_major, nvhost_minor + dev->index);
err = cdev_add(&ch->cdev, devno, 1);
if (err < 0) {
dev_err(&dev->dev,
"failed to add chan %i cdev\n", dev->index);
goto fail;
}
- ch->node = device_create(nvhost_get_host(dev)->nvhost_class, NULL, devno, NULL,
+ ch->node = device_create(nvhost_get_host(dev)->nvhost_class,
+ NULL, devno, NULL,
IFACE_NAME "-%s", dev->name);
if (IS_ERR(ch->node)) {
err = PTR_ERR(ch->node);
@@ -564,7 +580,11 @@ int nvhost_client_device_init(struct nvhost_device *dev)
{
int err;
struct nvhost_master *nvhost_master = nvhost_get_host(dev);
- struct nvhost_channel *ch = &nvhost_master->channels[dev->index];
+ struct nvhost_channel *ch;
+
+ ch = nvhost_alloc_channel(dev);
+ if (ch == NULL)
+ return -ENODEV;
/* store the pointer to this device for channel */
ch->dev = dev;
@@ -587,6 +607,7 @@ int nvhost_client_device_init(struct nvhost_device *dev)
fail:
/* Add clean-up */
+ nvhost_free_channel(ch);
return err;
}
diff --git a/drivers/video/tegra/host/bus_client.h b/drivers/video/tegra/host/bus_client.h
index adc3a704ea5d..e95ea0bc3401 100644
--- a/drivers/video/tegra/host/bus_client.h
+++ b/drivers/video/tegra/host/bus_client.h
@@ -24,10 +24,10 @@
#include <linux/types.h>
struct nvhost_device;
-void nvhost_read_module_regs(struct nvhost_device *ndev,
+int nvhost_read_module_regs(struct nvhost_device *ndev,
u32 offset, int count, u32 *values);
-void nvhost_write_module_regs(struct nvhost_device *ndev,
+int nvhost_write_module_regs(struct nvhost_device *ndev,
u32 offset, int count, const u32 *values);
int nvhost_client_user_init(struct nvhost_device *dev);
diff --git a/drivers/video/tegra/host/chip_support.c b/drivers/video/tegra/host/chip_support.c
new file mode 100644
index 000000000000..9abb1fa026a4
--- /dev/null
+++ b/drivers/video/tegra/host/chip_support.c
@@ -0,0 +1,56 @@
+/*
+ * drivers/video/tegra/host/chip_support.c
+ *
+ * Tegra Graphics Host Chip support module
+ *
+ * Copyright (c) 2012, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/errno.h>
+
+#include <mach/hardware.h>
+
+#include "bus.h"
+#include "chip_support.h"
+#include "t20/t20.h"
+#include "t30/t30.h"
+
+struct nvhost_chip_support *nvhost_get_chip_ops(void)
+{
+ return (nvhost_bus_get())->nvhost_chip_ops;
+}
+
+int nvhost_init_chip_support(struct nvhost_master *host)
+{
+ int err = 0;
+ struct nvhost_chip_support *chip_ops;
+
+ chip_ops = nvhost_get_chip_ops();
+
+ switch (tegra_get_chipid()) {
+ case TEGRA_CHIPID_TEGRA2:
+ err = nvhost_init_t20_support(host, chip_ops);
+ break;
+
+ case TEGRA_CHIPID_TEGRA3:
+ err = nvhost_init_t30_support(host, chip_ops);
+ break;
+
+ default:
+ err = -ENODEV;
+ }
+
+ return err;
+}
diff --git a/drivers/video/tegra/host/chip_support.h b/drivers/video/tegra/host/chip_support.h
index 6727e7a69fb4..f5d2811f143f 100644
--- a/drivers/video/tegra/host/chip_support.h
+++ b/drivers/video/tegra/host/chip_support.h
@@ -21,121 +21,160 @@
#define _NVHOST_CHIP_SUPPORT_H_
#include <linux/types.h>
+#include "bus.h"
+
struct output;
-struct nvhost_waitchk;
-struct nvhost_userctx_timeout;
+
struct nvhost_master;
+struct nvhost_intr;
+struct nvhost_syncpt;
+struct nvhost_userctx_timeout;
struct nvhost_channel;
-struct nvmap_handle;
-struct nvmap_client;
struct nvhost_hwctx;
struct nvhost_cdma;
-struct nvhost_intr;
+struct nvhost_job;
struct push_buffer;
struct nvhost_syncpt;
-struct nvhost_master;
struct dentry;
struct nvhost_job;
+struct nvhost_intr_syncpt;
+struct mem_handle;
+struct mem_mgr;
+struct nvhost_device;
+
+struct nvhost_channel_ops {
+ int (*init)(struct nvhost_channel *,
+ struct nvhost_master *,
+ int chid);
+ int (*submit)(struct nvhost_job *job);
+ int (*read3dreg)(struct nvhost_channel *channel,
+ struct nvhost_hwctx *hwctx,
+ u32 offset,
+ u32 *value);
+ int (*save_context)(struct nvhost_channel *channel);
+ int (*drain_read_fifo)(struct nvhost_channel *ch,
+ u32 *ptr, unsigned int count, unsigned int *pending);
+};
+
+struct nvhost_cdma_ops {
+ void (*start)(struct nvhost_cdma *);
+ void (*stop)(struct nvhost_cdma *);
+ void (*kick)(struct nvhost_cdma *);
+ int (*timeout_init)(struct nvhost_cdma *,
+ u32 syncpt_id);
+ void (*timeout_destroy)(struct nvhost_cdma *);
+ void (*timeout_teardown_begin)(struct nvhost_cdma *);
+ void (*timeout_teardown_end)(struct nvhost_cdma *,
+ u32 getptr);
+ void (*timeout_cpu_incr)(struct nvhost_cdma *,
+ u32 getptr,
+ u32 syncpt_incrs,
+ u32 syncval,
+ u32 nr_slots,
+ u32 waitbases);
+};
+
+struct nvhost_pushbuffer_ops {
+ void (*reset)(struct push_buffer *);
+ int (*init)(struct push_buffer *);
+ void (*destroy)(struct push_buffer *);
+ void (*push_to)(struct push_buffer *,
+ struct mem_mgr *, struct mem_handle *,
+ u32 op1, u32 op2);
+ void (*pop_from)(struct push_buffer *,
+ unsigned int slots);
+ u32 (*space)(struct push_buffer *);
+ u32 (*putptr)(struct push_buffer *);
+};
+
+struct nvhost_debug_ops {
+ void (*debug_init)(struct dentry *de);
+ void (*show_channel_cdma)(struct nvhost_master *,
+ struct nvhost_channel *,
+ struct output *,
+ int chid);
+ void (*show_channel_fifo)(struct nvhost_master *,
+ struct nvhost_channel *,
+ struct output *,
+ int chid);
+ void (*show_mlocks)(struct nvhost_master *m,
+ struct output *o);
+
+};
+
+struct nvhost_syncpt_ops {
+ void (*reset)(struct nvhost_syncpt *, u32 id);
+ void (*reset_wait_base)(struct nvhost_syncpt *, u32 id);
+ void (*read_wait_base)(struct nvhost_syncpt *, u32 id);
+ u32 (*update_min)(struct nvhost_syncpt *, u32 id);
+ void (*cpu_incr)(struct nvhost_syncpt *, u32 id);
+ int (*patch_wait)(struct nvhost_syncpt *sp,
+ void *patch_addr);
+ void (*debug)(struct nvhost_syncpt *);
+ const char * (*name)(struct nvhost_syncpt *, u32 id);
+ int (*mutex_try_lock)(struct nvhost_syncpt *,
+ unsigned int idx);
+ void (*mutex_unlock)(struct nvhost_syncpt *,
+ unsigned int idx);
+};
+
+struct nvhost_intr_ops {
+ void (*init_host_sync)(struct nvhost_intr *);
+ void (*set_host_clocks_per_usec)(
+ struct nvhost_intr *, u32 clocks);
+ void (*set_syncpt_threshold)(
+ struct nvhost_intr *, u32 id, u32 thresh);
+ void (*enable_syncpt_intr)(struct nvhost_intr *, u32 id);
+ void (*disable_all_syncpt_intrs)(struct nvhost_intr *);
+ int (*request_host_general_irq)(struct nvhost_intr *);
+ void (*free_host_general_irq)(struct nvhost_intr *);
+ int (*request_syncpt_irq)(struct nvhost_intr_syncpt *syncpt);
+};
+
+struct nvhost_dev_ops {
+ struct nvhost_channel *(*alloc_nvhost_channel)(
+ struct nvhost_device *dev);
+ void (*free_nvhost_channel)(struct nvhost_channel *ch);
+};
+
+struct nvhost_mem_ops {
+ struct mem_mgr *(*alloc_mgr)(void);
+ void (*put_mgr)(struct mem_mgr *);
+ struct mem_mgr *(*get_mgr)(struct mem_mgr *);
+ struct mem_mgr *(*get_mgr_file)(int fd);
+ struct mem_handle *(*alloc)(struct mem_mgr *,
+ size_t size, size_t align,
+ int flags);
+ struct mem_handle *(*get)(struct mem_mgr *, u32 id);
+ void (*put)(struct mem_mgr *, struct mem_handle *);
+ phys_addr_t (*pin)(struct mem_mgr *, struct mem_handle *);
+ void (*unpin)(struct mem_mgr *, struct mem_handle *);
+ void *(*mmap)(struct mem_handle *);
+ void (*munmap)(struct mem_handle *, void *);
+};
struct nvhost_chip_support {
- struct {
- int (*init)(struct nvhost_channel *,
- struct nvhost_master *,
- int chid);
- int (*submit)(struct nvhost_job *job);
- int (*read3dreg)(struct nvhost_channel *channel,
- struct nvhost_hwctx *hwctx,
- u32 offset,
- u32 *value);
- } channel;
-
- struct {
- void (*start)(struct nvhost_cdma *);
- void (*stop)(struct nvhost_cdma *);
- void (*kick)(struct nvhost_cdma *);
- int (*timeout_init)(struct nvhost_cdma *,
- u32 syncpt_id);
- void (*timeout_destroy)(struct nvhost_cdma *);
- void (*timeout_teardown_begin)(struct nvhost_cdma *);
- void (*timeout_teardown_end)(struct nvhost_cdma *,
- u32 getptr);
- void (*timeout_cpu_incr)(struct nvhost_cdma *,
- u32 getptr,
- u32 syncpt_incrs,
- u32 syncval,
- u32 nr_slots);
- void (*timeout_pb_incr)(struct nvhost_cdma *,
- u32 getptr,
- u32 syncpt_incrs,
- u32 nr_slots,
- bool exec_ctxsave);
- } cdma;
-
- struct {
- void (*reset)(struct push_buffer *);
- int (*init)(struct push_buffer *);
- void (*destroy)(struct push_buffer *);
- void (*push_to)(struct push_buffer *,
- struct nvmap_client *,
- struct nvmap_handle *,
- u32 op1, u32 op2);
- void (*pop_from)(struct push_buffer *,
- unsigned int slots);
- u32 (*space)(struct push_buffer *);
- u32 (*putptr)(struct push_buffer *);
- } push_buffer;
-
- struct {
- void (*debug_init)(struct dentry *de);
- void (*show_channel_cdma)(struct nvhost_master *,
- struct nvhost_channel *,
- struct output *,
- int chid);
- void (*show_channel_fifo)(struct nvhost_master *,
- struct nvhost_channel *,
- struct output *,
- int chid);
- void (*show_mlocks)(struct nvhost_master *m,
- struct output *o);
-
- } debug;
-
- struct {
- void (*reset)(struct nvhost_syncpt *, u32 id);
- void (*reset_wait_base)(struct nvhost_syncpt *, u32 id);
- void (*read_wait_base)(struct nvhost_syncpt *, u32 id);
- u32 (*update_min)(struct nvhost_syncpt *, u32 id);
- void (*cpu_incr)(struct nvhost_syncpt *, u32 id);
- int (*wait_check)(struct nvhost_syncpt *sp,
- struct nvmap_client *nvmap,
- u32 waitchk_mask,
- struct nvhost_waitchk *wait,
- int num_waitchk);
- void (*debug)(struct nvhost_syncpt *);
- const char * (*name)(struct nvhost_syncpt *, u32 id);
- int (*mutex_try_lock)(struct nvhost_syncpt *,
- unsigned int idx);
- void (*mutex_unlock)(struct nvhost_syncpt *,
- unsigned int idx);
- } syncpt;
-
- struct {
- void (*init_host_sync)(struct nvhost_intr *);
- void (*set_host_clocks_per_usec)(
- struct nvhost_intr *, u32 clocks);
- void (*set_syncpt_threshold)(
- struct nvhost_intr *, u32 id, u32 thresh);
- void (*enable_syncpt_intr)(struct nvhost_intr *, u32 id);
- void (*disable_all_syncpt_intrs)(struct nvhost_intr *);
- int (*request_host_general_irq)(struct nvhost_intr *);
- void (*free_host_general_irq)(struct nvhost_intr *);
- int (*request_syncpt_irq)(struct nvhost_intr_syncpt *syncpt);
- } intr;
-
- struct {
- struct nvhost_device *(*get_nvhost_device)(struct nvhost_master *host,
- char *name);
- } nvhost_dev;
+ struct nvhost_channel_ops channel;
+ struct nvhost_cdma_ops cdma;
+ struct nvhost_pushbuffer_ops push_buffer;
+ struct nvhost_debug_ops debug;
+ struct nvhost_syncpt_ops syncpt;
+ struct nvhost_intr_ops intr;
+ struct nvhost_dev_ops nvhost_dev;
+ struct nvhost_mem_ops mem;
};
+struct nvhost_chip_support *nvhost_get_chip_ops(void);
+
+#define host_device_op() nvhost_get_chip_ops()->nvhost_dev
+#define channel_cdma_op() nvhost_get_chip_ops()->cdma
+#define channel_op() nvhost_get_chip_ops()->channel
+#define syncpt_op() nvhost_get_chip_ops()->syncpt
+#define intr_op() nvhost_get_chip_ops()->intr
+#define cdma_op() nvhost_get_chip_ops()->cdma
+#define cdma_pb_op() nvhost_get_chip_ops()->push_buffer
+#define mem_op() (nvhost_get_chip_ops()->mem)
+
+int nvhost_init_chip_support(struct nvhost_master *);
+
#endif /* _NVHOST_CHIP_SUPPORT_H_ */
diff --git a/drivers/video/tegra/host/debug.c b/drivers/video/tegra/host/debug.c
index 91436c903fc6..58f9348b84bd 100644
--- a/drivers/video/tegra/host/debug.c
+++ b/drivers/video/tegra/host/debug.c
@@ -22,8 +22,12 @@
#include <linux/io.h>
+#include "bus.h"
#include "dev.h"
#include "debug.h"
+#include "nvhost_acm.h"
+#include "nvhost_channel.h"
+#include "chip_support.h"
pid_t nvhost_debug_null_kickoff_pid;
unsigned int nvhost_debug_trace_cmdbuf;
@@ -59,8 +63,8 @@ static int show_channels(struct device *dev, void *data)
mutex_lock(&ch->reflock);
if (ch->refcount) {
mutex_lock(&ch->cdma.lock);
- m->op.debug.show_channel_fifo(m, ch, o, nvdev->index);
- m->op.debug.show_channel_cdma(m, ch, o, nvdev->index);
+ nvhost_get_chip_ops()->debug.show_channel_fifo(m, ch, o, nvdev->index);
+ nvhost_get_chip_ops()->debug.show_channel_cdma(m, ch, o, nvdev->index);
mutex_unlock(&ch->cdma.lock);
}
mutex_unlock(&ch->reflock);
@@ -72,19 +76,19 @@ static int show_channels(struct device *dev, void *data)
static void show_syncpts(struct nvhost_master *m, struct output *o)
{
int i;
- BUG_ON(!m->op.syncpt.name);
+ BUG_ON(!nvhost_get_chip_ops()->syncpt.name);
nvhost_debug_output(o, "---- syncpts ----\n");
- for (i = 0; i < m->syncpt.nb_pts; i++) {
+ for (i = 0; i < nvhost_syncpt_nb_pts(&m->syncpt); i++) {
u32 max = nvhost_syncpt_read_max(&m->syncpt, i);
u32 min = nvhost_syncpt_update_min(&m->syncpt, i);
if (!min && !max)
continue;
nvhost_debug_output(o, "id %d (%s) min %d max %d\n",
- i, m->op.syncpt.name(&m->syncpt, i),
+ i, nvhost_get_chip_ops()->syncpt.name(&m->syncpt, i),
min, max);
}
- for (i = 0; i < m->syncpt.nb_bases; i++) {
+ for (i = 0; i < nvhost_syncpt_nb_pts(&m->syncpt); i++) {
u32 base_val;
base_val = nvhost_syncpt_read_wait_base(&m->syncpt, i);
if (base_val)
@@ -99,16 +103,56 @@ static void show_all(struct nvhost_master *m, struct output *o)
{
nvhost_module_busy(m->dev);
- m->op.debug.show_mlocks(m, o);
+ nvhost_get_chip_ops()->debug.show_mlocks(m, o);
show_syncpts(m, o);
nvhost_debug_output(o, "---- channels ----\n");
- bus_for_each_dev(&nvhost_bus_type, NULL, o, show_channels);
+ bus_for_each_dev(&(nvhost_bus_get())->nvhost_bus_type, NULL, o,
+ show_channels);
nvhost_module_idle(m->dev);
}
#ifdef CONFIG_DEBUG_FS
-static int nvhost_debug_show(struct seq_file *s, void *unused)
+static int show_channels_no_fifo(struct device *dev, void *data)
+{
+ struct nvhost_channel *ch;
+ struct nvhost_device *nvdev = to_nvhost_device(dev);
+ struct output *o = data;
+ struct nvhost_master *m;
+
+ if (nvdev == NULL)
+ return 0;
+
+ m = nvhost_get_host(nvdev);
+ ch = nvdev->channel;
+ if (ch) {
+ mutex_lock(&ch->reflock);
+ if (ch->refcount) {
+ mutex_lock(&ch->cdma.lock);
+ nvhost_get_chip_ops()->debug.show_channel_cdma(m,
+ ch, o, nvdev->index);
+ mutex_unlock(&ch->cdma.lock);
+ }
+ mutex_unlock(&ch->reflock);
+ }
+
+ return 0;
+}
+
+static void show_all_no_fifo(struct nvhost_master *m, struct output *o)
+{
+ nvhost_module_busy(m->dev);
+
+ nvhost_get_chip_ops()->debug.show_mlocks(m, o);
+ show_syncpts(m, o);
+ nvhost_debug_output(o, "---- channels ----\n");
+ bus_for_each_dev(&(nvhost_bus_get())->nvhost_bus_type, NULL, o,
+ show_channels_no_fifo);
+
+ nvhost_module_idle(m->dev);
+}
+
+static int nvhost_debug_show_all(struct seq_file *s, void *unused)
{
struct output o = {
.fn = write_to_seqfile,
@@ -117,6 +161,27 @@ static int nvhost_debug_show(struct seq_file *s, void *unused)
show_all(s->private, &o);
return 0;
}
+static int nvhost_debug_show(struct seq_file *s, void *unused)
+{
+ struct output o = {
+ .fn = write_to_seqfile,
+ .ctx = s
+ };
+ show_all_no_fifo(s->private, &o);
+ return 0;
+}
+
+static int nvhost_debug_open_all(struct inode *inode, struct file *file)
+{
+ return single_open(file, nvhost_debug_show_all, inode->i_private);
+}
+
+static const struct file_operations nvhost_debug_all_fops = {
+ .open = nvhost_debug_open_all,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
static int nvhost_debug_open(struct inode *inode, struct file *file)
{
@@ -136,14 +201,16 @@ void nvhost_debug_init(struct nvhost_master *master)
debugfs_create_file("status", S_IRUGO, de,
master, &nvhost_debug_fops);
+ debugfs_create_file("status_all", S_IRUGO, de,
+ master, &nvhost_debug_all_fops);
debugfs_create_u32("null_kickoff_pid", S_IRUGO|S_IWUSR, de,
&nvhost_debug_null_kickoff_pid);
debugfs_create_u32("trace_cmdbuf", S_IRUGO|S_IWUSR, de,
&nvhost_debug_trace_cmdbuf);
- if (master->op.debug.debug_init)
- master->op.debug.debug_init(de);
+ if (nvhost_get_chip_ops()->debug.debug_init)
+ nvhost_get_chip_ops()->debug.debug_init(de);
debugfs_create_u32("force_timeout_pid", S_IRUGO|S_IWUSR, de,
&nvhost_debug_force_timeout_pid);
diff --git a/drivers/video/tegra/host/dev.c b/drivers/video/tegra/host/dev.c
index 2e1ffeea7729..6200507548f7 100644
--- a/drivers/video/tegra/host/dev.c
+++ b/drivers/video/tegra/host/dev.c
@@ -18,568 +18,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/spinlock.h>
-#include <linux/fs.h>
-#include <linux/cdev.h>
-#include <linux/uaccess.h>
-#include <linux/file.h>
-#include <linux/clk.h>
-#include <linux/hrtimer.h>
-
-#include "dev.h"
#define CREATE_TRACE_POINTS
#include <trace/events/nvhost.h>
-#include <linux/io.h>
-
#include <linux/nvhost.h>
-#include <linux/nvhost_ioctl.h>
-#include <mach/nvmap.h>
#include <mach/gpufuse.h>
-#include <mach/hardware.h>
-#include <mach/iomap.h>
-
-#include "debug.h"
-#include "nvhost_job.h"
-#include "t20/t20.h"
-#include "t30/t30.h"
-#include "bus_client.h"
-
-#define DRIVER_NAME "host1x"
-
-int nvhost_major;
-int nvhost_minor;
-
-static unsigned int register_sets;
-
-struct nvhost_ctrl_userctx {
- struct nvhost_master *dev;
- u32 *mod_locks;
-};
-
-static int nvhost_ctrlrelease(struct inode *inode, struct file *filp)
-{
- struct nvhost_ctrl_userctx *priv = filp->private_data;
- int i;
-
- trace_nvhost_ctrlrelease(priv->dev->dev->name);
-
- filp->private_data = NULL;
- if (priv->mod_locks[0])
- nvhost_module_idle(priv->dev->dev);
- for (i = 1; i < priv->dev->syncpt.nb_mlocks; i++)
- if (priv->mod_locks[i])
- nvhost_mutex_unlock(&priv->dev->syncpt, i);
- kfree(priv->mod_locks);
- kfree(priv);
- return 0;
-}
-
-static int nvhost_ctrlopen(struct inode *inode, struct file *filp)
-{
- struct nvhost_master *host = container_of(inode->i_cdev, struct nvhost_master, cdev);
- struct nvhost_ctrl_userctx *priv;
- u32 *mod_locks;
-
- trace_nvhost_ctrlopen(host->dev->name);
-
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- mod_locks = kzalloc(sizeof(u32) * host->syncpt.nb_mlocks, GFP_KERNEL);
-
- if (!(priv && mod_locks)) {
- kfree(priv);
- kfree(mod_locks);
- return -ENOMEM;
- }
-
- priv->dev = host;
- priv->mod_locks = mod_locks;
- filp->private_data = priv;
- return 0;
-}
-
-static int nvhost_ioctl_ctrl_syncpt_read(struct nvhost_ctrl_userctx *ctx,
- struct nvhost_ctrl_syncpt_read_args *args)
-{
- if (args->id >= ctx->dev->syncpt.nb_pts)
- return -EINVAL;
- args->value = nvhost_syncpt_read(&ctx->dev->syncpt, args->id);
- trace_nvhost_ioctl_ctrl_syncpt_read(args->id, args->value);
- return 0;
-}
-
-static int nvhost_ioctl_ctrl_syncpt_incr(struct nvhost_ctrl_userctx *ctx,
- struct nvhost_ctrl_syncpt_incr_args *args)
-{
- if (args->id >= ctx->dev->syncpt.nb_pts)
- return -EINVAL;
- trace_nvhost_ioctl_ctrl_syncpt_incr(args->id);
- nvhost_syncpt_incr(&ctx->dev->syncpt, args->id);
- return 0;
-}
-
-static int nvhost_ioctl_ctrl_syncpt_waitex(struct nvhost_ctrl_userctx *ctx,
- struct nvhost_ctrl_syncpt_waitex_args *args)
-{
- u32 timeout;
- int err;
- if (args->id >= ctx->dev->syncpt.nb_pts)
- return -EINVAL;
- if (args->timeout == NVHOST_NO_TIMEOUT)
- timeout = MAX_SCHEDULE_TIMEOUT;
- else
- timeout = (u32)msecs_to_jiffies(args->timeout);
-
- err = nvhost_syncpt_wait_timeout(&ctx->dev->syncpt, args->id,
- args->thresh, timeout, &args->value);
- trace_nvhost_ioctl_ctrl_syncpt_wait(args->id, args->thresh,
- args->timeout, args->value, err);
-
- return err;
-}
-
-static int nvhost_ioctl_ctrl_module_mutex(struct nvhost_ctrl_userctx *ctx,
- struct nvhost_ctrl_module_mutex_args *args)
-{
- int err = 0;
- if (args->id >= ctx->dev->syncpt.nb_mlocks ||
- args->lock > 1)
- return -EINVAL;
-
- trace_nvhost_ioctl_ctrl_module_mutex(args->lock, args->id);
- if (args->lock && !ctx->mod_locks[args->id]) {
- if (args->id == 0)
- nvhost_module_busy(ctx->dev->dev);
- else
- err = nvhost_mutex_try_lock(&ctx->dev->syncpt,
- args->id);
- if (!err)
- ctx->mod_locks[args->id] = 1;
- } else if (!args->lock && ctx->mod_locks[args->id]) {
- if (args->id == 0)
- nvhost_module_idle(ctx->dev->dev);
- else
- nvhost_mutex_unlock(&ctx->dev->syncpt, args->id);
- ctx->mod_locks[args->id] = 0;
- }
- return err;
-}
-
-static struct nvhost_device *get_ndev_by_moduleid(struct nvhost_master *host,
- u32 id)
-{
- int i;
-
- for (i = 0; i < host->nb_channels; i++) {
- struct nvhost_device *ndev = host->channels[i].dev;
-
- /* display and dsi do not use channel for register programming.
- * so their channels do not have device instance.
- * hence skip such channels from here. */
- if (ndev == NULL)
- continue;
-
- if (id == ndev->moduleid)
- return ndev;
- }
- return NULL;
-}
-
-static int nvhost_ioctl_ctrl_module_regrdwr(struct nvhost_ctrl_userctx *ctx,
- struct nvhost_ctrl_module_regrdwr_args *args)
-{
- u32 num_offsets = args->num_offsets;
- u32 *offsets = args->offsets;
- u32 *values = args->values;
- u32 vals[64];
- struct nvhost_device *ndev;
-
- trace_nvhost_ioctl_ctrl_module_regrdwr(args->id,
- args->num_offsets, args->write);
- /* Check that there is something to read and that block size is
- * u32 aligned */
- if (num_offsets == 0 || args->block_size & 3)
- return -EINVAL;
-
- ndev = get_ndev_by_moduleid(ctx->dev, args->id);
- if (!ndev)
- return -EINVAL;
-
- while (num_offsets--) {
- int remaining = args->block_size >> 2;
- u32 offs;
- if (get_user(offs, offsets))
- return -EFAULT;
- offsets++;
- while (remaining) {
- int batch = min(remaining, 64);
- if (args->write) {
- if (copy_from_user(vals, values,
- batch*sizeof(u32)))
- return -EFAULT;
- nvhost_write_module_regs(ndev,
- offs, batch, vals);
- } else {
- nvhost_read_module_regs(ndev,
- offs, batch, vals);
- if (copy_to_user(values, vals,
- batch*sizeof(u32)))
- return -EFAULT;
- }
- remaining -= batch;
- offs += batch;
- values += batch;
- }
- }
-
- return 0;
-}
-
-static int nvhost_ioctl_ctrl_get_version(struct nvhost_ctrl_userctx *ctx,
- struct nvhost_get_param_args *args)
-{
- args->value = NVHOST_SUBMIT_VERSION_MAX_SUPPORTED;
- return 0;
-}
-
-static long nvhost_ctrlctl(struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- struct nvhost_ctrl_userctx *priv = filp->private_data;
- u8 buf[NVHOST_IOCTL_CTRL_MAX_ARG_SIZE];
- int err = 0;
-
- if ((_IOC_TYPE(cmd) != NVHOST_IOCTL_MAGIC) ||
- (_IOC_NR(cmd) == 0) ||
- (_IOC_NR(cmd) > NVHOST_IOCTL_CTRL_LAST))
- return -EFAULT;
-
- BUG_ON(_IOC_SIZE(cmd) > NVHOST_IOCTL_CTRL_MAX_ARG_SIZE);
-
- if (_IOC_DIR(cmd) & _IOC_WRITE) {
- if (copy_from_user(buf, (void __user *)arg, _IOC_SIZE(cmd)))
- return -EFAULT;
- }
-
- switch (cmd) {
- case NVHOST_IOCTL_CTRL_SYNCPT_READ:
- err = nvhost_ioctl_ctrl_syncpt_read(priv, (void *)buf);
- break;
- case NVHOST_IOCTL_CTRL_SYNCPT_INCR:
- err = nvhost_ioctl_ctrl_syncpt_incr(priv, (void *)buf);
- break;
- case NVHOST_IOCTL_CTRL_SYNCPT_WAIT:
- err = nvhost_ioctl_ctrl_syncpt_waitex(priv, (void *)buf);
- break;
- case NVHOST_IOCTL_CTRL_MODULE_MUTEX:
- err = nvhost_ioctl_ctrl_module_mutex(priv, (void *)buf);
- break;
- case NVHOST_IOCTL_CTRL_MODULE_REGRDWR:
- err = nvhost_ioctl_ctrl_module_regrdwr(priv, (void *)buf);
- break;
- case NVHOST_IOCTL_CTRL_SYNCPT_WAITEX:
- err = nvhost_ioctl_ctrl_syncpt_waitex(priv, (void *)buf);
- break;
- case NVHOST_IOCTL_CTRL_GET_VERSION:
- err = nvhost_ioctl_ctrl_get_version(priv, (void *)buf);
- break;
- default:
- err = -ENOTTY;
- break;
- }
-
- if ((err == 0) && (_IOC_DIR(cmd) & _IOC_READ))
- err = copy_to_user((void __user *)arg, buf, _IOC_SIZE(cmd));
-
- return err;
-}
-
-static const struct file_operations nvhost_ctrlops = {
- .owner = THIS_MODULE,
- .release = nvhost_ctrlrelease,
- .open = nvhost_ctrlopen,
- .unlocked_ioctl = nvhost_ctrlctl
-};
-
-static void power_on_host(struct nvhost_device *dev)
-{
- struct nvhost_master *host = nvhost_get_drvdata(dev);
- nvhost_syncpt_reset(&host->syncpt);
- nvhost_intr_start(&host->intr, clk_get_rate(dev->clk[0]));
-}
-
-static int power_off_host(struct nvhost_device *dev)
-{
- struct nvhost_master *host = nvhost_get_drvdata(dev);
- nvhost_syncpt_save(&host->syncpt);
- nvhost_intr_stop(&host->intr);
- return 0;
-}
-
-static int __devinit nvhost_user_init(struct nvhost_master *host)
-{
- int err, devno;
-
- host->nvhost_class = class_create(THIS_MODULE, IFACE_NAME);
- if (IS_ERR(host->nvhost_class)) {
- err = PTR_ERR(host->nvhost_class);
- dev_err(&host->dev->dev, "failed to create class\n");
- goto fail;
- }
-
- err = alloc_chrdev_region(&devno, nvhost_minor,
- host->nb_channels + 1, IFACE_NAME);
- nvhost_major = MAJOR(devno);
- if (err < 0) {
- dev_err(&host->dev->dev, "failed to reserve chrdev region\n");
- goto fail;
- }
-
- cdev_init(&host->cdev, &nvhost_ctrlops);
- host->cdev.owner = THIS_MODULE;
- devno = MKDEV(nvhost_major, nvhost_minor + host->nb_channels);
- err = cdev_add(&host->cdev, devno, 1);
- if (err < 0)
- goto fail;
- host->ctrl = device_create(host->nvhost_class, NULL, devno, NULL,
- IFACE_NAME "-ctrl");
- if (IS_ERR(host->ctrl)) {
- err = PTR_ERR(host->ctrl);
- dev_err(&host->dev->dev, "failed to create ctrl device\n");
- goto fail;
- }
-
- return 0;
-fail:
- return err;
-}
-
-struct nvhost_device *nvhost_get_device(char *name)
-{
- BUG_ON(!host_device_op(nvhost).get_nvhost_device);
- return host_device_op(nvhost).get_nvhost_device(nvhost, name);
-}
-
-static void nvhost_remove_chip_support(struct nvhost_master *host)
-{
- kfree(host->channels);
- host->channels = 0;
-
- kfree(host->intr.syncpt);
- host->intr.syncpt = 0;
-}
-
-static int __devinit nvhost_init_chip_support(struct nvhost_master *host)
-{
- int err;
- switch (tegra_get_chipid()) {
- case TEGRA_CHIPID_TEGRA2:
- err = nvhost_init_t20_support(host);
- break;
-
- case TEGRA_CHIPID_TEGRA3:
- err = nvhost_init_t30_support(host);
- break;
- default:
- return -ENODEV;
- }
-
- if (err)
- return err;
-
- /* allocate items sized in chip specific support init */
- host->channels = kzalloc(sizeof(struct nvhost_channel) *
- host->nb_channels, GFP_KERNEL);
-
- host->intr.syncpt = kzalloc(sizeof(struct nvhost_intr_syncpt) *
- host->syncpt.nb_pts, GFP_KERNEL);
-
- if (!(host->channels && host->intr.syncpt)) {
- /* frees happen in the support removal phase */
- return -ENOMEM;
- }
-
- return 0;
-}
-
-static struct resource nvhost_resources[] = {
- {
- .start = TEGRA_HOST1X_BASE,
- .end = TEGRA_HOST1X_BASE + TEGRA_HOST1X_SIZE - 1,
- .flags = IORESOURCE_MEM,
- },
- {
- .start = INT_SYNCPT_THRESH_BASE,
- .end = INT_SYNCPT_THRESH_BASE + INT_SYNCPT_THRESH_NR - 1,
- .flags = IORESOURCE_IRQ,
- },
- {
- .start = INT_HOST1X_MPCORE_GENERAL,
- .end = INT_HOST1X_MPCORE_GENERAL,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-struct nvhost_device tegra_grhost_device = {
- .name = DRIVER_NAME,
- .id = -1,
- .resource = nvhost_resources,
- .num_resources = ARRAY_SIZE(nvhost_resources),
- .finalize_poweron = power_on_host,
- .prepare_poweroff = power_off_host,
- .clocks = {{"host1x", UINT_MAX}, {} },
- NVHOST_MODULE_NO_POWERGATE_IDS,
-};
-
-static int __devinit nvhost_probe(struct nvhost_device *dev)
-{
- struct nvhost_master *host;
- struct resource *regs, *intr0, *intr1;
- int i, err;
-
- regs = nvhost_get_resource(dev, IORESOURCE_MEM, 0);
- intr0 = nvhost_get_resource(dev, IORESOURCE_IRQ, 0);
- intr1 = nvhost_get_resource(dev, IORESOURCE_IRQ, 1);
-
- if (!regs || !intr0 || !intr1) {
- dev_err(&dev->dev, "missing required platform resources\n");
- return -ENXIO;
- }
-
- host = kzalloc(sizeof(*host), GFP_KERNEL);
- if (!host)
- return -ENOMEM;
-
- host->nvmap = nvmap_create_client(nvmap_dev, "nvhost");
- if (!host->nvmap) {
- dev_err(&dev->dev, "unable to create nvmap client\n");
- err = -EIO;
- goto fail;
- }
-
- host->reg_mem = request_mem_region(regs->start,
- resource_size(regs), dev->name);
- if (!host->reg_mem) {
- dev_err(&dev->dev, "failed to get host register memory\n");
- err = -ENXIO;
- goto fail;
- }
-
- host->aperture = ioremap(regs->start, resource_size(regs));
- if (!host->aperture) {
- dev_err(&dev->dev, "failed to remap host registers\n");
- err = -ENXIO;
- goto fail;
- }
-
- err = nvhost_init_chip_support(host);
- if (err) {
- dev_err(&dev->dev, "failed to init chip support\n");
- goto fail;
- }
-
- /* Register host1x device as bus master */
- host->dev = dev;
-
- /* Give pointer to host1x via driver */
- nvhost_set_drvdata(dev, host);
-
- nvhost_bus_add_host(host);
-
- err = nvhost_syncpt_init(&tegra_grhost_device, &host->syncpt);
- if (err)
- goto fail;
-
- err = nvhost_intr_init(&host->intr, intr1->start, intr0->start);
- if (err)
- goto fail;
-
- err = nvhost_user_init(host);
- if (err)
- goto fail;
-
- err = nvhost_module_init(&tegra_grhost_device);
- if (err)
- goto fail;
-
- for (i = 0; i < host->dev->num_clks; i++)
- clk_enable(host->dev->clk[i]);
- nvhost_syncpt_reset(&host->syncpt);
- for (i = 0; i < host->dev->num_clks; i++)
- clk_disable(host->dev->clk[0]);
-
- nvhost_debug_init(host);
-
- dev_info(&dev->dev, "initialized\n");
- return 0;
-
-fail:
- nvhost_remove_chip_support(host);
- if (host->nvmap)
- nvmap_client_put(host->nvmap);
- kfree(host);
- return err;
-}
-
-static int __exit nvhost_remove(struct nvhost_device *dev)
-{
- struct nvhost_master *host = nvhost_get_drvdata(dev);
- nvhost_intr_deinit(&host->intr);
- nvhost_syncpt_deinit(&host->syncpt);
- nvhost_remove_chip_support(host);
- return 0;
-}
-
-static int nvhost_suspend(struct nvhost_device *dev, pm_message_t state)
-{
- struct nvhost_master *host = nvhost_get_drvdata(dev);
- int ret = 0;
-
- ret = nvhost_module_suspend(host->dev);
- dev_info(&dev->dev, "suspend status: %d\n", ret);
-
- return ret;
-}
-
-static int nvhost_resume(struct nvhost_device *dev)
-{
- dev_info(&dev->dev, "resuming\n");
- return 0;
-}
-
-static struct nvhost_driver nvhost_driver = {
- .probe = nvhost_probe,
- .remove = __exit_p(nvhost_remove),
- .suspend = nvhost_suspend,
- .resume = nvhost_resume,
- .driver = {
- .owner = THIS_MODULE,
- .name = DRIVER_NAME
- }
-};
-
-static int __init nvhost_mod_init(void)
-{
- register_sets = tegra_gpu_register_sets();
- return nvhost_driver_register(&nvhost_driver);
-}
-
-static void __exit nvhost_mod_exit(void)
-{
- nvhost_driver_unregister(&nvhost_driver);
-}
-
-/* host1x master device needs nvmap to be instantiated first.
- * nvmap is instantiated via fs_initcall.
- * Hence instantiate host1x master device using rootfs_initcall
- * which is one level after fs_initcall. */
-rootfs_initcall(nvhost_mod_init);
-module_exit(nvhost_mod_exit);
-
-module_param_call(register_sets, NULL, param_get_uint, &register_sets, 0444);
-MODULE_PARM_DESC(register_sets, "Number of register sets");
MODULE_AUTHOR("NVIDIA");
MODULE_DESCRIPTION("Graphics host driver for Tegra products");
diff --git a/drivers/video/tegra/host/dev.h b/drivers/video/tegra/host/dev.h
index 74d7e16fc272..53ec2de13aa1 100644
--- a/drivers/video/tegra/host/dev.h
+++ b/drivers/video/tegra/host/dev.h
@@ -1,9 +1,7 @@
/*
* drivers/video/tegra/host/dev.h
*
- * Tegra Graphics Host Driver Entrypoint
- *
- * Copyright (c) 2010-2012, NVIDIA Corporation.
+ * Copyright (c) 2012, NVIDIA Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -18,51 +16,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef __NVHOST_DEV_H
-#define __NVHOST_DEV_H
-
-#include "nvhost_acm.h"
-#include "nvhost_syncpt.h"
-#include "nvhost_intr.h"
-#include "nvhost_channel.h"
-#include "chip_support.h"
-
-#define TRACE_MAX_LENGTH 128U
-#define IFACE_NAME "nvhost"
-
-extern int nvhost_major;
-extern int nvhost_minor;
-
-struct nvhost_hwctx;
-
-struct nvhost_master {
- void __iomem *aperture;
- void __iomem *sync_aperture;
- struct resource *reg_mem;
- struct class *nvhost_class;
- struct cdev cdev;
- struct device *ctrl;
- struct nvhost_syncpt syncpt;
- struct nvmap_client *nvmap;
- struct nvhost_intr intr;
- struct nvhost_device *dev;
- struct nvhost_channel *channels;
- u32 nb_channels;
-
- struct nvhost_chip_support op;
-
- atomic_t clientid;
-};
-
-extern struct nvhost_master *nvhost;
-
-void nvhost_debug_init(struct nvhost_master *master);
-void nvhost_debug_dump(struct nvhost_master *master);
-
-#define host_device_op(host) (host->op.nvhost_dev)
-
-struct nvhost_device *nvhost_get_device(char *name);
+#ifndef NVHOST_DEV_H
+#define NVHOST_DEV_H
-extern pid_t nvhost_debug_null_kickoff_pid;
+#include "host1x/host1x.h"
#endif
diff --git a/drivers/video/tegra/host/dsi/Makefile b/drivers/video/tegra/host/dsi/Makefile
deleted file mode 100644
index eb94d3ec4928..000000000000
--- a/drivers/video/tegra/host/dsi/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-GCOV_PROFILE := y
-EXTRA_CFLAGS += -Idrivers/video/tegra/host
-
-nvhost-dsi-objs = \
- dsi.o
-
-obj-$(CONFIG_TEGRA_GRHOST) += nvhost-dsi.o
diff --git a/drivers/video/tegra/host/dsi/dsi.c b/drivers/video/tegra/host/dsi/dsi.c
deleted file mode 100644
index 0e49f591574d..000000000000
--- a/drivers/video/tegra/host/dsi/dsi.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * drivers/video/tegra/host/dsi/dsi.c
- *
- * Tegra Graphics DSI
- *
- * Copyright (c) 2012, NVIDIA Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "dev.h"
-#include "bus_client.h"
-
-static int dsi_probe(struct nvhost_device *dev)
-{
- return nvhost_client_device_init(dev);
-}
-
-static int __exit dsi_remove(struct nvhost_device *dev)
-{
- /* Add clean-up */
- return 0;
-}
-
-static int dsi_suspend(struct nvhost_device *dev, pm_message_t state)
-{
- return nvhost_client_device_suspend(dev);
-}
-
-static int dsi_resume(struct nvhost_device *dev)
-{
- dev_info(&dev->dev, "resuming\n");
- return 0;
-}
-
-struct nvhost_device *dsi_device;
-
-static struct nvhost_driver dsi_driver = {
- .probe = dsi_probe,
- .remove = __exit_p(dsi_remove),
-#ifdef CONFIG_PM
- .suspend = dsi_suspend,
- .resume = dsi_resume,
-#endif
- .driver = {
- .owner = THIS_MODULE,
- .name = "dsi",
- }
-};
-
-static int __init dsi_init(void)
-{
- int err;
-
- dsi_device = nvhost_get_device("dsi");
- if (!dsi_device)
- return -ENXIO;
-
- err = nvhost_device_register(dsi_device);
- if (err)
- return err;
-
- return nvhost_driver_register(&dsi_driver);
-}
-
-static void __exit dsi_exit(void)
-{
- nvhost_driver_unregister(&dsi_driver);
-}
-
-module_init(dsi_init);
-module_exit(dsi_exit);
diff --git a/drivers/video/tegra/host/gr2d/gr2d.c b/drivers/video/tegra/host/gr2d/gr2d.c
index f88eb72e0a40..56752eba5951 100644
--- a/drivers/video/tegra/host/gr2d/gr2d.c
+++ b/drivers/video/tegra/host/gr2d/gr2d.c
@@ -21,7 +21,8 @@
#include "dev.h"
#include "bus_client.h"
-static int __devinit gr2d_probe(struct nvhost_device *dev)
+static int __devinit gr2d_probe(struct nvhost_device *dev,
+ struct nvhost_device_id *id_table)
{
return nvhost_client_device_init(dev);
}
@@ -32,6 +33,7 @@ static int __exit gr2d_remove(struct nvhost_device *dev)
return 0;
}
+#ifdef CONFIG_PM
static int gr2d_suspend(struct nvhost_device *dev, pm_message_t state)
{
return nvhost_client_device_suspend(dev);
@@ -42,8 +44,7 @@ static int gr2d_resume(struct nvhost_device *dev)
dev_info(&dev->dev, "resuming\n");
return 0;
}
-
-struct nvhost_device *gr2d_device;
+#endif
static struct nvhost_driver gr2d_driver = {
.probe = gr2d_probe,
@@ -60,16 +61,6 @@ static struct nvhost_driver gr2d_driver = {
static int __init gr2d_init(void)
{
- int err;
-
- gr2d_device = nvhost_get_device("gr2d");
- if (!gr2d_device)
- return -ENXIO;
-
- err = nvhost_device_register(gr2d_device);
- if (err)
- return err;
-
return nvhost_driver_register(&gr2d_driver);
}
diff --git a/drivers/video/tegra/host/gr3d/gr3d.c b/drivers/video/tegra/host/gr3d/gr3d.c
index f387d54e585e..715468131d9e 100644
--- a/drivers/video/tegra/host/gr3d/gr3d.c
+++ b/drivers/video/tegra/host/gr3d/gr3d.c
@@ -18,27 +18,27 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <mach/nvmap.h>
#include <linux/slab.h>
+#include <mach/gpufuse.h>
#include "t20/t20.h"
-#include "host1x/host1x_channel.h"
-#include "host1x/host1x_hardware.h"
-#include "host1x/host1x_syncpt.h"
+#include "host1x/host1x01_hardware.h"
#include "nvhost_hwctx.h"
#include "dev.h"
#include "gr3d.h"
+#include "gr3d_t20.h"
+#include "gr3d_t30.h"
+#include "scale3d.h"
#include "bus_client.h"
-
-#ifndef TEGRA_POWERGATE_3D1
-#define TEGRA_POWERGATE_3D1 -1
-#endif
+#include "nvhost_channel.h"
+#include "nvhost_memmgr.h"
+#include "chip_support.h"
void nvhost_3dctx_restore_begin(struct host1x_hwctx_handler *p, u32 *ptr)
{
/* set class to host */
ptr[0] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
- NV_CLASS_HOST_INCR_SYNCPT_BASE, 1);
+ host1x_uclass_incr_syncpt_base_r(), 1);
/* increment sync point base */
ptr[1] = nvhost_class_host_incr_syncpt_base(p->waitbase,
p->restore_incrs);
@@ -64,28 +64,27 @@ void nvhost_3dctx_restore_end(struct host1x_hwctx_handler *p, u32 *ptr)
{
/* syncpt increment to track restore gather. */
ptr[0] = nvhost_opcode_imm_incr_syncpt(
- NV_SYNCPT_OP_DONE, p->syncpt);
+ host1x_uclass_incr_syncpt_cond_op_done_v(), p->syncpt);
}
/*** ctx3d ***/
-
struct host1x_hwctx *nvhost_3dctx_alloc_common(struct host1x_hwctx_handler *p,
struct nvhost_channel *ch, bool map_restore)
{
- struct nvmap_client *nvmap = nvhost_get_host(ch->dev)->nvmap;
+ struct mem_mgr *memmgr = nvhost_get_host(ch->dev)->memmgr;
struct host1x_hwctx *ctx;
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return NULL;
- ctx->restore = nvmap_alloc(nvmap, p->restore_size * 4, 32,
- map_restore ? NVMAP_HANDLE_WRITE_COMBINE
- : NVMAP_HANDLE_UNCACHEABLE, 0);
+ ctx->restore = mem_op().alloc(memmgr, p->restore_size * 4, 32,
+ map_restore ? mem_mgr_flag_write_combine
+ : mem_mgr_flag_uncacheable);
if (IS_ERR_OR_NULL(ctx->restore))
goto fail;
if (map_restore) {
- ctx->restore_virt = nvmap_mmap(ctx->restore);
+ ctx->restore_virt = mem_op().mmap(ctx->restore);
if (!ctx->restore_virt)
goto fail;
} else
@@ -98,7 +97,7 @@ struct host1x_hwctx *nvhost_3dctx_alloc_common(struct host1x_hwctx_handler *p,
ctx->save_incrs = p->save_incrs;
ctx->save_thresh = p->save_thresh;
ctx->save_slots = p->save_slots;
- ctx->restore_phys = nvmap_pin(nvmap, ctx->restore);
+ ctx->restore_phys = mem_op().pin(memmgr, ctx->restore);
if (IS_ERR_VALUE(ctx->restore_phys))
goto fail;
@@ -108,10 +107,10 @@ struct host1x_hwctx *nvhost_3dctx_alloc_common(struct host1x_hwctx_handler *p,
fail:
if (map_restore && ctx->restore_virt) {
- nvmap_munmap(ctx->restore, ctx->restore_virt);
+ mem_op().munmap(ctx->restore, ctx->restore_virt);
ctx->restore_virt = NULL;
}
- nvmap_free(nvmap, ctx->restore);
+ mem_op().put(memmgr, ctx->restore);
ctx->restore = NULL;
kfree(ctx);
return NULL;
@@ -126,16 +125,15 @@ void nvhost_3dctx_free(struct kref *ref)
{
struct nvhost_hwctx *nctx = container_of(ref, struct nvhost_hwctx, ref);
struct host1x_hwctx *ctx = to_host1x_hwctx(nctx);
- struct nvmap_client *nvmap =
- nvhost_get_host(nctx->channel->dev)->nvmap;
+ struct mem_mgr *memmgr = nvhost_get_host(nctx->channel->dev)->memmgr;
if (ctx->restore_virt) {
- nvmap_munmap(ctx->restore, ctx->restore_virt);
+ mem_op().munmap(ctx->restore, ctx->restore_virt);
ctx->restore_virt = NULL;
}
- nvmap_unpin(nvmap, ctx->restore);
+ mem_op().unpin(memmgr, ctx->restore);
ctx->restore_phys = 0;
- nvmap_free(nvmap, ctx->restore);
+ mem_op().put(memmgr, ctx->restore);
ctx->restore = NULL;
kfree(ctx);
}
@@ -147,11 +145,74 @@ void nvhost_3dctx_put(struct nvhost_hwctx *ctx)
int nvhost_gr3d_prepare_power_off(struct nvhost_device *dev)
{
- return host1x_save_context(dev, NVSYNCPT_3D);
+ return nvhost_channel_save_context(dev->channel);
}
-static int __devinit gr3d_probe(struct nvhost_device *dev)
+enum gr3d_ip_ver {
+ gr3d_01 = 1,
+ gr3d_02,
+};
+
+struct gr3d_desc {
+ void (*finalize_poweron)(struct nvhost_device *dev);
+ void (*busy)(struct nvhost_device *);
+ void (*idle)(struct nvhost_device *);
+ void (*suspend_ndev)(struct nvhost_device *);
+ void (*init)(struct nvhost_device *dev);
+ void (*deinit)(struct nvhost_device *dev);
+ int (*prepare_poweroff)(struct nvhost_device *dev);
+ struct nvhost_hwctx_handler *(*alloc_hwctx_handler)(u32 syncpt,
+ u32 waitbase, struct nvhost_channel *ch);
+};
+
+static const struct gr3d_desc gr3d[] = {
+ [gr3d_01] = {
+ .finalize_poweron = NULL,
+ .busy = NULL,
+ .idle = NULL,
+ .suspend_ndev = NULL,
+ .init = NULL,
+ .deinit = NULL,
+ .prepare_poweroff = nvhost_gr3d_prepare_power_off,
+ .alloc_hwctx_handler = nvhost_gr3d_t20_ctxhandler_init,
+ },
+ [gr3d_02] = {
+ .finalize_poweron = NULL,
+ .busy = nvhost_scale3d_notify_busy,
+ .idle = nvhost_scale3d_notify_idle,
+ .suspend_ndev = nvhost_scale3d_suspend,
+ .init = nvhost_scale3d_init,
+ .deinit = nvhost_scale3d_deinit,
+ .prepare_poweroff = nvhost_gr3d_prepare_power_off,
+ .alloc_hwctx_handler = nvhost_gr3d_t30_ctxhandler_init,
+ },
+};
+
+static struct nvhost_device_id gr3d_id[] = {
+ { "gr3d", gr3d_01 },
+ { "gr3d", gr3d_02 },
+ { },
+};
+
+MODULE_DEVICE_TABLE(nvhost, gr3d_id);
+
+static int __devinit gr3d_probe(struct nvhost_device *dev,
+ struct nvhost_device_id *id_table)
{
+ int index = 0;
+ struct nvhost_driver *drv = to_nvhost_driver(dev->dev.driver);
+
+ index = id_table->version;
+
+ drv->finalize_poweron = gr3d[index].finalize_poweron;
+ drv->busy = gr3d[index].busy;
+ drv->idle = gr3d[index].idle;
+ drv->suspend_ndev = gr3d[index].suspend_ndev;
+ drv->init = gr3d[index].init;
+ drv->deinit = gr3d[index].deinit;
+ drv->prepare_poweroff = gr3d[index].prepare_poweroff;
+ drv->alloc_hwctx_handler = gr3d[index].alloc_hwctx_handler;
+
return nvhost_client_device_init(dev);
}
@@ -161,6 +222,7 @@ static int __exit gr3d_remove(struct nvhost_device *dev)
return 0;
}
+#ifdef CONFIG_PM
static int gr3d_suspend(struct nvhost_device *dev, pm_message_t state)
{
return nvhost_client_device_suspend(dev);
@@ -171,8 +233,7 @@ static int gr3d_resume(struct nvhost_device *dev)
dev_info(&dev->dev, "resuming\n");
return 0;
}
-
-struct nvhost_device *gr3d_device;
+#endif
static struct nvhost_driver gr3d_driver = {
.probe = gr3d_probe,
@@ -184,21 +245,12 @@ static struct nvhost_driver gr3d_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "gr3d",
- }
+ },
+ .id_table = gr3d_id,
};
static int __init gr3d_init(void)
{
- int err;
-
- gr3d_device = nvhost_get_device("gr3d");
- if (!gr3d_device)
- return -ENXIO;
-
- err = nvhost_device_register(gr3d_device);
- if (err)
- return err;
-
return nvhost_driver_register(&gr3d_driver);
}
diff --git a/drivers/video/tegra/host/gr3d/gr3d_t20.c b/drivers/video/tegra/host/gr3d/gr3d_t20.c
index 9ca990f89077..b6e3896fe50c 100644
--- a/drivers/video/tegra/host/gr3d/gr3d_t20.c
+++ b/drivers/video/tegra/host/gr3d/gr3d_t20.c
@@ -19,11 +19,12 @@
*/
#include "nvhost_hwctx.h"
-#include "dev.h"
-#include "host1x/host1x_channel.h"
-#include "host1x/host1x_hardware.h"
-#include "host1x/host1x_syncpt.h"
+#include "nvhost_channel.h"
+#include "host1x/host1x.h"
+#include "host1x/host1x01_hardware.h"
#include "gr3d.h"
+#include "chip_support.h"
+#include "nvhost_memmgr.h"
#include <linux/slab.h>
@@ -136,8 +137,9 @@ static void save_push_v0(struct nvhost_hwctx *nctx, struct nvhost_cdma *cdma)
struct host1x_hwctx_handler *p = host1x_hwctx_handler(ctx);
nvhost_cdma_push_gather(cdma,
- (void *)NVHOST_CDMA_PUSH_GATHER_CTXSAVE,
- (void *)NVHOST_CDMA_PUSH_GATHER_CTXSAVE,
+ nvhost_get_host(nctx->channel->dev)->memmgr,
+ p->save_buf,
+ 0,
nvhost_opcode_gather(p->save_size),
p->save_phys);
}
@@ -146,24 +148,26 @@ static void __init save_begin_v0(struct host1x_hwctx_handler *h, u32 *ptr)
{
/* 3d: when done, increment syncpt to base+1 */
ptr[0] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0);
- ptr[1] = nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_OP_DONE,
+ ptr[1] = nvhost_opcode_imm_incr_syncpt(
+ host1x_uclass_incr_syncpt_cond_op_done_v(),
h->syncpt); /* incr 1 */
/* host: wait for syncpt base+1 */
ptr[2] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
- NV_CLASS_HOST_WAIT_SYNCPT_BASE, 1);
+ host1x_uclass_wait_syncpt_base_r(), 1);
ptr[3] = nvhost_class_host_wait_syncpt_base(h->syncpt,
h->waitbase, 1);
/* host: signal context read thread to start reading */
- ptr[4] = nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_IMMEDIATE,
+ ptr[4] = nvhost_opcode_imm_incr_syncpt(
+ host1x_uclass_incr_syncpt_cond_immediate_v(),
h->syncpt); /* incr 2 */
}
static void __init save_direct_v0(u32 *ptr, u32 start_reg, u32 count)
{
- ptr[0] = nvhost_opcode_nonincr(NV_CLASS_HOST_INDOFF, 1);
+ ptr[0] = nvhost_opcode_nonincr(host1x_uclass_indoff_r(), 1);
ptr[1] = nvhost_class_host_indoff_reg_read(NV_HOST_MODULE_GR3D,
start_reg, true);
- ptr[2] = nvhost_opcode_nonincr(NV_CLASS_HOST_INDDATA, count);
+ ptr[2] = nvhost_opcode_nonincr(host1x_uclass_inddata_r(), count);
}
static void __init save_indirect_v0(u32 *ptr, u32 offset_reg, u32 offset,
@@ -173,28 +177,28 @@ static void __init save_indirect_v0(u32 *ptr, u32 offset_reg, u32 offset,
offset_reg, 1);
ptr[1] = offset;
ptr[2] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
- NV_CLASS_HOST_INDOFF, 1);
+ host1x_uclass_indoff_r(), 1);
ptr[3] = nvhost_class_host_indoff_reg_read(NV_HOST_MODULE_GR3D,
data_reg, false);
- ptr[4] = nvhost_opcode_nonincr(NV_CLASS_HOST_INDDATA, count);
+ ptr[4] = nvhost_opcode_nonincr(host1x_uclass_inddata_r(), count);
}
static void __init save_end_v0(struct host1x_hwctx_handler *h, u32 *ptr)
{
/* Wait for context read service to finish (cpu incr 3) */
- ptr[0] = nvhost_opcode_nonincr(NV_CLASS_HOST_WAIT_SYNCPT_BASE, 1);
+ ptr[0] = nvhost_opcode_nonincr(host1x_uclass_wait_syncpt_base_r(), 1);
ptr[1] = nvhost_class_host_wait_syncpt_base(h->syncpt,
h->waitbase, h->save_incrs);
/* Advance syncpoint base */
- ptr[2] = nvhost_opcode_nonincr(NV_CLASS_HOST_INCR_SYNCPT_BASE, 1);
- ptr[3] = nvhost_class_host_incr_syncpt_base(NVWAITBASE_3D,
+ ptr[2] = nvhost_opcode_nonincr(host1x_uclass_incr_syncpt_base_r(), 1);
+ ptr[3] = nvhost_class_host_incr_syncpt_base(h->waitbase,
h->save_incrs);
/* set class back to the unit */
ptr[4] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0);
}
static u32 *save_regs_v0(u32 *ptr, unsigned int *pending,
- void __iomem *chan_regs,
+ struct nvhost_channel *ch,
const struct hwctx_reginfo *regs,
unsigned int nr_regs)
{
@@ -212,7 +216,7 @@ static u32 *save_regs_v0(u32 *ptr, unsigned int *pending,
ptr += RESTORE_INDIRECT_SIZE;
break;
}
- drain_result = host1x_drain_read_fifo(chan_regs,
+ drain_result = nvhost_channel_drain_read_fifo(ch,
ptr, count, pending);
BUG_ON(drain_result < 0);
ptr += count;
@@ -338,7 +342,7 @@ static void ctx3d_save_service(struct nvhost_hwctx *nctx)
u32 *ptr = (u32 *)ctx->restore_virt + RESTORE_BEGIN_SIZE;
unsigned int pending = 0;
- ptr = save_regs_v0(ptr, &pending, nctx->channel->aperture,
+ ptr = save_regs_v0(ptr, &pending, nctx->channel,
ctxsave_regs_3d_global,
ARRAY_SIZE(ctxsave_regs_3d_global));
@@ -351,22 +355,22 @@ struct nvhost_hwctx_handler *nvhost_gr3d_t20_ctxhandler_init(
u32 syncpt, u32 waitbase,
struct nvhost_channel *ch)
{
- struct nvmap_client *nvmap;
+ struct mem_mgr *memmgr;
u32 *save_ptr;
struct host1x_hwctx_handler *p;
p = kmalloc(sizeof(*p), GFP_KERNEL);
if (!p)
return NULL;
- nvmap = nvhost_get_host(ch->dev)->nvmap;
+ memmgr = nvhost_get_host(ch->dev)->memmgr;
p->syncpt = syncpt;
p->waitbase = waitbase;
setup_save(p, NULL);
- p->save_buf = nvmap_alloc(nvmap, p->save_size * sizeof(u32), 32,
- NVMAP_HANDLE_WRITE_COMBINE, 0);
+ p->save_buf = mem_op().alloc(memmgr, p->save_size * sizeof(u32), 32,
+ mem_mgr_flag_write_combine);
if (IS_ERR(p->save_buf)) {
p->save_buf = NULL;
return NULL;
@@ -374,14 +378,14 @@ struct nvhost_hwctx_handler *nvhost_gr3d_t20_ctxhandler_init(
p->save_slots = 1;
- save_ptr = nvmap_mmap(p->save_buf);
+ save_ptr = mem_op().mmap(p->save_buf);
if (!save_ptr) {
- nvmap_free(nvmap, p->save_buf);
+ mem_op().put(memmgr, p->save_buf);
p->save_buf = NULL;
return NULL;
}
- p->save_phys = nvmap_pin(nvmap, p->save_buf);
+ p->save_phys = mem_op().pin(memmgr, p->save_buf);
setup_save(p, save_ptr);
diff --git a/drivers/video/tegra/host/gr3d/gr3d_t20.h b/drivers/video/tegra/host/gr3d/gr3d_t20.h
index 5fe6d50d0c30..e6fb8fdf8aba 100644
--- a/drivers/video/tegra/host/gr3d/gr3d_t20.h
+++ b/drivers/video/tegra/host/gr3d/gr3d_t20.h
@@ -21,7 +21,10 @@
#ifndef __NVHOST_GR3D_GR3D_T20_H
#define __NVHOST_GR3D_GR3D_T20_H
+#include <linux/types.h>
+
struct nvhost_hwctx_handler;
+struct nvhost_channel;
struct nvhost_hwctx_handler *nvhost_gr3d_t20_ctxhandler_init(
u32 syncpt, u32 waitbase,
diff --git a/drivers/video/tegra/host/gr3d/gr3d_t30.c b/drivers/video/tegra/host/gr3d/gr3d_t30.c
index ab4d04f89ab2..c35fea2f3ac2 100644
--- a/drivers/video/tegra/host/gr3d/gr3d_t30.c
+++ b/drivers/video/tegra/host/gr3d/gr3d_t30.c
@@ -19,18 +19,18 @@
*/
#include "nvhost_hwctx.h"
+#include "nvhost_channel.h"
+#include "nvhost_cdma.h"
#include "dev.h"
-#include "host1x/host1x_hardware.h"
-#include "host1x/host1x_syncpt.h"
+#include "host1x/host1x01_hardware.h"
#include "gr3d.h"
+#include "chip_support.h"
+#include "nvhost_memmgr.h"
#include <mach/gpufuse.h>
#include <mach/hardware.h>
#include <linux/slab.h>
-/* 99 > 2, which makes kernel panic if register set is incorrect */
-static int register_sets = 99;
-
static const struct hwctx_reginfo ctxsave_regs_3d_global[] = {
HWCTX_REGINFO(0xe00, 4, DIRECT),
HWCTX_REGINFO(0xe05, 30, DIRECT),
@@ -112,28 +112,29 @@ static void save_push_v1(struct nvhost_hwctx *nctx, struct nvhost_cdma *cdma)
/* wait for 3d idle */
nvhost_cdma_push(cdma,
nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0),
- nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_OP_DONE,
- p->syncpt));
+ nvhost_opcode_imm_incr_syncpt(
+ host1x_uclass_incr_syncpt_cond_op_done_v(),
+ p->syncpt));
nvhost_cdma_push(cdma,
nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
- NV_CLASS_HOST_WAIT_SYNCPT_BASE, 1),
+ host1x_uclass_wait_syncpt_base_r(), 1),
nvhost_class_host_wait_syncpt_base(p->syncpt,
p->waitbase, 1));
/* back to 3d */
nvhost_cdma_push(cdma,
nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0),
NVHOST_OPCODE_NOOP);
+
/* set register set 0 and 1 register read memory output addresses,
and send their reads to memory */
- if (register_sets == 2) {
- nvhost_cdma_push(cdma,
- nvhost_opcode_imm(AR3D_GSHIM_WRITE_MASK, 2),
- nvhost_opcode_imm(AR3D_GLOBAL_MEMORY_OUTPUT_READS,
- 1));
- nvhost_cdma_push(cdma,
- nvhost_opcode_nonincr(0x904, 1),
- ctx->restore_phys + restore_set1_offset * 4);
- }
+
+ nvhost_cdma_push(cdma,
+ nvhost_opcode_imm(AR3D_GSHIM_WRITE_MASK, 2),
+ nvhost_opcode_imm(AR3D_GLOBAL_MEMORY_OUTPUT_READS, 1));
+ nvhost_cdma_push(cdma,
+ nvhost_opcode_nonincr(0x904, 1),
+ ctx->restore_phys + restore_set1_offset * 4);
+
nvhost_cdma_push(cdma,
nvhost_opcode_imm(AR3D_GSHIM_WRITE_MASK, 1),
nvhost_opcode_imm(AR3D_GLOBAL_MEMORY_OUTPUT_READS, 1));
@@ -142,8 +143,9 @@ static void save_push_v1(struct nvhost_hwctx *nctx, struct nvhost_cdma *cdma)
ctx->restore_phys);
/* gather the save buffer */
nvhost_cdma_push_gather(cdma,
- (void *)NVHOST_CDMA_PUSH_GATHER_CTXSAVE,
- (void *)NVHOST_CDMA_PUSH_GATHER_CTXSAVE,
+ nvhost_get_host(nctx->channel->dev)->memmgr,
+ p->save_buf,
+ 0,
nvhost_opcode_gather(p->save_size),
p->save_phys);
}
@@ -163,11 +165,11 @@ static void __init save_direct_v1(u32 *ptr, u32 start_reg, u32 count)
nvhost_3dctx_restore_direct(ptr + 1, start_reg, count);
ptr += RESTORE_DIRECT_SIZE;
ptr[1] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
- NV_CLASS_HOST_INDOFF, 1);
+ host1x_uclass_indoff_r(), 1);
ptr[2] = nvhost_class_host_indoff_reg_read(NV_HOST_MODULE_GR3D,
start_reg, true);
/* TODO could do this in the setclass if count < 6 */
- ptr[3] = nvhost_opcode_nonincr(NV_CLASS_HOST_INDDATA, count);
+ ptr[3] = nvhost_opcode_nonincr(host1x_uclass_inddata_r(), count);
}
static void __init save_indirect_v1(u32 *ptr, u32 offset_reg, u32 offset,
@@ -181,10 +183,10 @@ static void __init save_indirect_v1(u32 *ptr, u32 offset_reg, u32 offset,
ptr += RESTORE_INDIRECT_SIZE;
ptr[2] = nvhost_opcode_imm(offset_reg, offset);
ptr[3] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
- NV_CLASS_HOST_INDOFF, 1);
+ host1x_uclass_indoff_r(), 1);
ptr[4] = nvhost_class_host_indoff_reg_read(NV_HOST_MODULE_GR3D,
data_reg, false);
- ptr[5] = nvhost_opcode_nonincr(NV_CLASS_HOST_INDDATA, count);
+ ptr[5] = nvhost_opcode_nonincr(host1x_uclass_inddata_r(), count);
}
static void __init save_end_v1(struct host1x_hwctx_handler *p, u32 *ptr)
@@ -196,15 +198,16 @@ static void __init save_end_v1(struct host1x_hwctx_handler *p, u32 *ptr)
ptr += RESTORE_END_SIZE;
/* reset to dual reg if necessary */
ptr[1] = nvhost_opcode_imm(AR3D_GSHIM_WRITE_MASK,
- (1 << register_sets) - 1);
+ (1 << 2) - 1);
/* op_done syncpt incr to flush FDC */
- ptr[2] = nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_OP_DONE, p->syncpt);
+ ptr[2] = nvhost_opcode_imm_incr_syncpt(
+ host1x_uclass_incr_syncpt_cond_op_done_v(), p->syncpt);
/* host wait for that syncpt incr, and advance the wait base */
ptr[3] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
- NV_CLASS_HOST_WAIT_SYNCPT_BASE,
+ host1x_uclass_wait_syncpt_base_r(),
nvhost_mask2(
- NV_CLASS_HOST_WAIT_SYNCPT_BASE,
- NV_CLASS_HOST_INCR_SYNCPT_BASE));
+ host1x_uclass_wait_syncpt_base_r(),
+ host1x_uclass_incr_syncpt_base_r()));
ptr[4] = nvhost_class_host_wait_syncpt_base(p->syncpt,
p->waitbase, p->save_incrs - 1);
ptr[5] = nvhost_class_host_incr_syncpt_base(p->waitbase,
@@ -311,16 +314,13 @@ static void __init setup_save(struct host1x_hwctx_handler *p, u32 *ptr)
};
int save_end_size = SAVE_END_V1_SIZE;
- BUG_ON(register_sets > 2);
-
if (info.ptr) {
save_begin_v1(p, info.ptr);
info.ptr += SAVE_BEGIN_V1_SIZE;
}
/* read from set0, write cmds through set0, restore to set0 and 1 */
- if (register_sets == 2)
- switch_gpu(&info, 0, 1, 3);
+ switch_gpu(&info, 0, 1, 3);
/* save regs that are common to both sets */
setup_save_regs(&info,
@@ -328,28 +328,26 @@ static void __init setup_save(struct host1x_hwctx_handler *p, u32 *ptr)
ARRAY_SIZE(ctxsave_regs_3d_global));
/* read from set 0, write cmds through set0, restore to set0 */
- if (register_sets == 2)
- switch_gpu(&info, 0, 1, 1);
+ switch_gpu(&info, 0, 1, 1);
/* save set 0 specific regs */
setup_save_regs(&info,
ctxsave_regs_3d_perset,
ARRAY_SIZE(ctxsave_regs_3d_perset));
- if (register_sets == 2) {
- /* read from set1, write cmds through set1, restore to set1 */
- switch_gpu(&info, 1, 2, 2);
- /* note offset at which set 1 restore starts */
- restore_set1_offset = info.restore_count;
- /* save set 1 specific regs */
- setup_save_regs(&info,
- ctxsave_regs_3d_perset,
- ARRAY_SIZE(ctxsave_regs_3d_perset));
- }
+
+ /* read from set1, write cmds through set1, restore to set1 */
+ switch_gpu(&info, 1, 2, 2);
+ /* note offset at which set 1 restore starts */
+ restore_set1_offset = info.restore_count;
+ /* save set 1 specific regs */
+ setup_save_regs(&info,
+ ctxsave_regs_3d_perset,
+ ARRAY_SIZE(ctxsave_regs_3d_perset));
+
/* read from set0, write cmds through set1, restore to set0 and 1 */
- if (register_sets == 2)
- switch_gpu(&info, 0, 2, 3);
+ switch_gpu(&info, 0, 2, 3);
if (info.ptr) {
save_end_v1(p, info.ptr);
@@ -384,7 +382,7 @@ struct nvhost_hwctx_handler *nvhost_gr3d_t30_ctxhandler_init(
u32 syncpt, u32 waitbase,
struct nvhost_channel *ch)
{
- struct nvmap_client *nvmap;
+ struct mem_mgr *memmgr;
u32 *save_ptr;
struct host1x_hwctx_handler *p;
@@ -392,38 +390,35 @@ struct nvhost_hwctx_handler *nvhost_gr3d_t30_ctxhandler_init(
if (!p)
return NULL;
- nvmap = nvhost_get_host(ch->dev)->nvmap;
-
- register_sets = tegra_gpu_register_sets();
- BUG_ON(register_sets == 0 || register_sets > 2);
+ memmgr = nvhost_get_host(ch->dev)->memmgr;
p->syncpt = syncpt;
p->waitbase = waitbase;
setup_save(p, NULL);
- p->save_buf = nvmap_alloc(nvmap, p->save_size * 4, 32,
- NVMAP_HANDLE_WRITE_COMBINE, 0);
+ p->save_buf = mem_op().alloc(memmgr, p->save_size * 4, 32,
+ mem_mgr_flag_write_combine);
if (IS_ERR(p->save_buf)) {
p->save_buf = NULL;
return NULL;
}
- p->save_slots = 6;
- if (register_sets == 2)
- p->save_slots += 2;
+ p->save_slots = 8;
- save_ptr = nvmap_mmap(p->save_buf);
+ save_ptr = mem_op().mmap(p->save_buf);
if (!save_ptr) {
- nvmap_free(nvmap, p->save_buf);
+ mem_op().put(memmgr, p->save_buf);
p->save_buf = NULL;
return NULL;
}
- p->save_phys = nvmap_pin(nvmap, p->save_buf);
+ p->save_phys = mem_op().pin(memmgr, p->save_buf);
setup_save(p, save_ptr);
+ mem_op().munmap(p->save_buf, save_ptr);
+
p->h.alloc = ctx3d_alloc_v1;
p->h.save_push = save_push_v1;
p->h.save_service = NULL;
diff --git a/drivers/video/tegra/host/gr3d/gr3d_t30.h b/drivers/video/tegra/host/gr3d/gr3d_t30.h
index d1b787e14b44..94d5dc0f353b 100644
--- a/drivers/video/tegra/host/gr3d/gr3d_t30.h
+++ b/drivers/video/tegra/host/gr3d/gr3d_t30.h
@@ -21,7 +21,10 @@
#ifndef __NVHOST_GR3D_GR3D_T30_H
#define __NVHOST_GR3D_GR3D_T30_H
+#include <linux/types.h>
+
struct nvhost_hwctx_handler;
+struct nvhost_channel;
struct nvhost_hwctx_handler *nvhost_gr3d_t30_ctxhandler_init(
u32 syncpt, u32 waitbase,
diff --git a/drivers/video/tegra/host/host1x/Makefile b/drivers/video/tegra/host/host1x/Makefile
index c3214ffe147b..76664945e12b 100644
--- a/drivers/video/tegra/host/host1x/Makefile
+++ b/drivers/video/tegra/host/host1x/Makefile
@@ -3,10 +3,6 @@ GCOV_PROFILE := y
EXTRA_CFLAGS += -Idrivers/video/tegra/host
nvhost-host1x-objs = \
- host1x_syncpt.o \
- host1x_channel.o \
- host1x_intr.o \
- host1x_cdma.o \
- host1x_debug.o
+ host1x.o
obj-$(CONFIG_TEGRA_GRHOST) += nvhost-host1x.o
diff --git a/drivers/video/tegra/host/host1x/host1x.c b/drivers/video/tegra/host/host1x/host1x.c
new file mode 100644
index 000000000000..33ebc1ff5d22
--- /dev/null
+++ b/drivers/video/tegra/host/host1x/host1x.c
@@ -0,0 +1,537 @@
+/*
+ * drivers/video/tegra/host/dev.c
+ *
+ * Tegra Graphics Host Driver Entrypoint
+ *
+ * Copyright (c) 2010-2012, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/uaccess.h>
+#include <linux/file.h>
+#include <linux/clk.h>
+
+#include "dev.h"
+#include "bus.h"
+#include <trace/events/nvhost.h>
+
+#include <linux/nvhost.h>
+#include <linux/nvhost_ioctl.h>
+
+#include "debug.h"
+#include "bus_client.h"
+#include "nvhost_acm.h"
+#include "nvhost_channel.h"
+#include "nvhost_job.h"
+
+#define DRIVER_NAME "host1x"
+
+struct nvhost_ctrl_userctx {
+ struct nvhost_master *dev;
+ u32 *mod_locks;
+};
+
+static int nvhost_ctrlrelease(struct inode *inode, struct file *filp)
+{
+ struct nvhost_ctrl_userctx *priv = filp->private_data;
+ int i;
+
+ trace_nvhost_ctrlrelease(priv->dev->dev->name);
+
+ filp->private_data = NULL;
+ if (priv->mod_locks[0])
+ nvhost_module_idle(priv->dev->dev);
+ for (i = 1; i < nvhost_syncpt_nb_mlocks(&priv->dev->syncpt); i++)
+ if (priv->mod_locks[i])
+ nvhost_mutex_unlock(&priv->dev->syncpt, i);
+ kfree(priv->mod_locks);
+ kfree(priv);
+ return 0;
+}
+
+static int nvhost_ctrlopen(struct inode *inode, struct file *filp)
+{
+ struct nvhost_master *host =
+ container_of(inode->i_cdev, struct nvhost_master, cdev);
+ struct nvhost_ctrl_userctx *priv;
+ u32 *mod_locks;
+
+ trace_nvhost_ctrlopen(host->dev->name);
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ mod_locks = kzalloc(sizeof(u32)
+ * nvhost_syncpt_nb_mlocks(&host->syncpt),
+ GFP_KERNEL);
+
+ if (!(priv && mod_locks)) {
+ kfree(priv);
+ kfree(mod_locks);
+ return -ENOMEM;
+ }
+
+ priv->dev = host;
+ priv->mod_locks = mod_locks;
+ filp->private_data = priv;
+ return 0;
+}
+
+static int nvhost_ioctl_ctrl_syncpt_read(struct nvhost_ctrl_userctx *ctx,
+ struct nvhost_ctrl_syncpt_read_args *args)
+{
+ if (args->id >= nvhost_syncpt_nb_pts(&ctx->dev->syncpt))
+ return -EINVAL;
+ args->value = nvhost_syncpt_read(&ctx->dev->syncpt, args->id);
+ trace_nvhost_ioctl_ctrl_syncpt_read(args->id, args->value);
+ return 0;
+}
+
+static int nvhost_ioctl_ctrl_syncpt_incr(struct nvhost_ctrl_userctx *ctx,
+ struct nvhost_ctrl_syncpt_incr_args *args)
+{
+ if (args->id >= nvhost_syncpt_nb_pts(&ctx->dev->syncpt))
+ return -EINVAL;
+ trace_nvhost_ioctl_ctrl_syncpt_incr(args->id);
+ nvhost_syncpt_incr(&ctx->dev->syncpt, args->id);
+ return 0;
+}
+
+static int nvhost_ioctl_ctrl_syncpt_waitex(struct nvhost_ctrl_userctx *ctx,
+ struct nvhost_ctrl_syncpt_waitex_args *args)
+{
+ u32 timeout;
+ int err;
+ if (args->id >= nvhost_syncpt_nb_pts(&ctx->dev->syncpt))
+ return -EINVAL;
+ if (args->timeout == NVHOST_NO_TIMEOUT)
+ timeout = MAX_SCHEDULE_TIMEOUT;
+ else
+ timeout = (u32)msecs_to_jiffies(args->timeout);
+
+ err = nvhost_syncpt_wait_timeout(&ctx->dev->syncpt, args->id,
+ args->thresh, timeout, &args->value);
+ trace_nvhost_ioctl_ctrl_syncpt_wait(args->id, args->thresh,
+ args->timeout, args->value, err);
+
+ return err;
+}
+
+static int nvhost_ioctl_ctrl_module_mutex(struct nvhost_ctrl_userctx *ctx,
+ struct nvhost_ctrl_module_mutex_args *args)
+{
+ int err = 0;
+ if (args->id >= nvhost_syncpt_nb_mlocks(&ctx->dev->syncpt) ||
+ args->lock > 1)
+ return -EINVAL;
+
+ trace_nvhost_ioctl_ctrl_module_mutex(args->lock, args->id);
+ if (args->lock && !ctx->mod_locks[args->id]) {
+ if (args->id == 0)
+ nvhost_module_busy(ctx->dev->dev);
+ else
+ err = nvhost_mutex_try_lock(&ctx->dev->syncpt,
+ args->id);
+ if (!err)
+ ctx->mod_locks[args->id] = 1;
+ } else if (!args->lock && ctx->mod_locks[args->id]) {
+ if (args->id == 0)
+ nvhost_module_idle(ctx->dev->dev);
+ else
+ nvhost_mutex_unlock(&ctx->dev->syncpt, args->id);
+ ctx->mod_locks[args->id] = 0;
+ }
+ return err;
+}
+
+static int match_by_moduleid(struct device *dev, void *data)
+{
+ struct nvhost_device *ndev = to_nvhost_device(dev);
+ u32 id = (u32)data;
+
+ return id == ndev->moduleid;
+}
+
+static struct nvhost_device *get_ndev_by_moduleid(struct nvhost_master *host,
+ u32 id)
+{
+ struct device *dev = bus_find_device(&nvhost_bus_inst->nvhost_bus_type,
+ NULL, (void *)id, match_by_moduleid);
+
+ return dev ? to_nvhost_device(dev) : NULL;
+}
+
+static int nvhost_ioctl_ctrl_module_regrdwr(struct nvhost_ctrl_userctx *ctx,
+ struct nvhost_ctrl_module_regrdwr_args *args)
+{
+ u32 num_offsets = args->num_offsets;
+ u32 *offsets = args->offsets;
+ u32 *values = args->values;
+ u32 vals[64];
+ struct nvhost_device *ndev;
+
+ trace_nvhost_ioctl_ctrl_module_regrdwr(args->id,
+ args->num_offsets, args->write);
+ /* Check that there is something to read and that block size is
+ * u32 aligned */
+ if (num_offsets == 0 || args->block_size & 3)
+ return -EINVAL;
+
+ ndev = get_ndev_by_moduleid(ctx->dev, args->id);
+ if (!ndev)
+ return -EINVAL;
+
+ while (num_offsets--) {
+ int err;
+ int remaining = args->block_size >> 2;
+ u32 offs;
+ if (get_user(offs, offsets))
+ return -EFAULT;
+ offsets++;
+ while (remaining) {
+ int batch = min(remaining, 64);
+ if (args->write) {
+ if (copy_from_user(vals, values,
+ batch*sizeof(u32)))
+ return -EFAULT;
+ err = nvhost_write_module_regs(ndev,
+ offs, batch, vals);
+ if (err)
+ return err;
+ } else {
+ err = nvhost_read_module_regs(ndev,
+ offs, batch, vals);
+ if (err)
+ return err;
+ if (copy_to_user(values, vals,
+ batch*sizeof(u32)))
+ return -EFAULT;
+ }
+ remaining -= batch;
+ offs += batch*sizeof(u32);
+ values += batch;
+ }
+ }
+
+ return 0;
+}
+
+static int nvhost_ioctl_ctrl_get_version(struct nvhost_ctrl_userctx *ctx,
+ struct nvhost_get_param_args *args)
+{
+ args->value = NVHOST_SUBMIT_VERSION_MAX_SUPPORTED;
+ return 0;
+}
+
+static long nvhost_ctrlctl(struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ struct nvhost_ctrl_userctx *priv = filp->private_data;
+ u8 buf[NVHOST_IOCTL_CTRL_MAX_ARG_SIZE];
+ int err = 0;
+
+ if ((_IOC_TYPE(cmd) != NVHOST_IOCTL_MAGIC) ||
+ (_IOC_NR(cmd) == 0) ||
+ (_IOC_NR(cmd) > NVHOST_IOCTL_CTRL_LAST) ||
+ (_IOC_SIZE(cmd) > NVHOST_IOCTL_CTRL_MAX_ARG_SIZE))
+ return -EFAULT;
+
+ if (_IOC_DIR(cmd) & _IOC_WRITE) {
+ if (copy_from_user(buf, (void __user *)arg, _IOC_SIZE(cmd)))
+ return -EFAULT;
+ }
+
+ switch (cmd) {
+ case NVHOST_IOCTL_CTRL_SYNCPT_READ:
+ err = nvhost_ioctl_ctrl_syncpt_read(priv, (void *)buf);
+ break;
+ case NVHOST_IOCTL_CTRL_SYNCPT_INCR:
+ err = nvhost_ioctl_ctrl_syncpt_incr(priv, (void *)buf);
+ break;
+ case NVHOST_IOCTL_CTRL_SYNCPT_WAIT:
+ err = nvhost_ioctl_ctrl_syncpt_waitex(priv, (void *)buf);
+ break;
+ case NVHOST_IOCTL_CTRL_MODULE_MUTEX:
+ err = nvhost_ioctl_ctrl_module_mutex(priv, (void *)buf);
+ break;
+ case NVHOST_IOCTL_CTRL_MODULE_REGRDWR:
+ err = nvhost_ioctl_ctrl_module_regrdwr(priv, (void *)buf);
+ break;
+ case NVHOST_IOCTL_CTRL_SYNCPT_WAITEX:
+ err = nvhost_ioctl_ctrl_syncpt_waitex(priv, (void *)buf);
+ break;
+ case NVHOST_IOCTL_CTRL_GET_VERSION:
+ err = nvhost_ioctl_ctrl_get_version(priv, (void *)buf);
+ break;
+ default:
+ err = -ENOTTY;
+ break;
+ }
+
+ if ((err == 0) && (_IOC_DIR(cmd) & _IOC_READ))
+ err = copy_to_user((void __user *)arg, buf, _IOC_SIZE(cmd));
+
+ return err;
+}
+
+static const struct file_operations nvhost_ctrlops = {
+ .owner = THIS_MODULE,
+ .release = nvhost_ctrlrelease,
+ .open = nvhost_ctrlopen,
+ .unlocked_ioctl = nvhost_ctrlctl
+};
+
+static void power_on_host(struct nvhost_device *dev)
+{
+ struct nvhost_master *host = nvhost_get_drvdata(dev);
+ nvhost_syncpt_reset(&host->syncpt);
+ nvhost_intr_start(&host->intr, clk_get_rate(dev->clk[0]));
+}
+
+static int power_off_host(struct nvhost_device *dev)
+{
+ struct nvhost_master *host = nvhost_get_drvdata(dev);
+ nvhost_syncpt_save(&host->syncpt);
+ nvhost_intr_stop(&host->intr);
+ return 0;
+}
+
+static int __devinit nvhost_user_init(struct nvhost_master *host)
+{
+ int err, devno;
+
+ host->nvhost_class = class_create(THIS_MODULE, IFACE_NAME);
+ if (IS_ERR(host->nvhost_class)) {
+ err = PTR_ERR(host->nvhost_class);
+ dev_err(&host->dev->dev, "failed to create class\n");
+ goto fail;
+ }
+
+ err = alloc_chrdev_region(&devno, 0, 1, IFACE_NAME);
+ if (err < 0) {
+ dev_err(&host->dev->dev, "failed to reserve chrdev region\n");
+ goto fail;
+ }
+
+ cdev_init(&host->cdev, &nvhost_ctrlops);
+ host->cdev.owner = THIS_MODULE;
+ err = cdev_add(&host->cdev, devno, 1);
+ if (err < 0)
+ goto fail;
+ host->ctrl = device_create(host->nvhost_class, NULL, devno, NULL,
+ IFACE_NAME "-ctrl");
+ if (IS_ERR(host->ctrl)) {
+ err = PTR_ERR(host->ctrl);
+ dev_err(&host->dev->dev, "failed to create ctrl device\n");
+ goto fail;
+ }
+
+ return 0;
+fail:
+ return err;
+}
+
+struct nvhost_channel *nvhost_alloc_channel(struct nvhost_device *dev)
+{
+ BUG_ON(!host_device_op().alloc_nvhost_channel);
+ return host_device_op().alloc_nvhost_channel(dev);
+}
+
+void nvhost_free_channel(struct nvhost_channel *ch)
+{
+ BUG_ON(!host_device_op().free_nvhost_channel);
+ host_device_op().free_nvhost_channel(ch);
+}
+
+static void nvhost_free_resources(struct nvhost_master *host)
+{
+ kfree(host->intr.syncpt);
+ host->intr.syncpt = 0;
+}
+
+static int __devinit nvhost_alloc_resources(struct nvhost_master *host)
+{
+ int err;
+
+ err = nvhost_init_chip_support(host);
+ if (err)
+ return err;
+
+ host->intr.syncpt = kzalloc(sizeof(struct nvhost_intr_syncpt) *
+ nvhost_syncpt_nb_pts(&host->syncpt),
+ GFP_KERNEL);
+
+ if (!host->intr.syncpt) {
+ /* frees happen in the support removal phase */
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int __devinit nvhost_probe(struct nvhost_device *dev,
+ struct nvhost_device_id *id_table)
+{
+ struct nvhost_master *host;
+ struct resource *regs, *intr0, *intr1;
+ int i, err;
+
+ regs = nvhost_get_resource(dev, IORESOURCE_MEM, 0);
+ intr0 = nvhost_get_resource(dev, IORESOURCE_IRQ, 0);
+ intr1 = nvhost_get_resource(dev, IORESOURCE_IRQ, 1);
+
+ if (!regs || !intr0 || !intr1) {
+ dev_err(&dev->dev, "missing required platform resources\n");
+ return -ENXIO;
+ }
+
+ host = kzalloc(sizeof(*host), GFP_KERNEL);
+ if (!host)
+ return -ENOMEM;
+
+ /* Register host1x device as bus master */
+ host->dev = dev;
+
+ /* Copy host1x parameters */
+ memcpy(&host->info, dev->dev.platform_data,
+ sizeof(struct host1x_device_info));
+
+ host->reg_mem = request_mem_region(regs->start,
+ resource_size(regs), dev->name);
+ if (!host->reg_mem) {
+ dev_err(&dev->dev, "failed to get host register memory\n");
+ err = -ENXIO;
+ goto fail;
+ }
+
+ host->aperture = ioremap(regs->start, resource_size(regs));
+ if (!host->aperture) {
+ dev_err(&dev->dev, "failed to remap host registers\n");
+ err = -ENXIO;
+ goto fail;
+ }
+
+ err = nvhost_alloc_resources(host);
+ if (err) {
+ dev_err(&dev->dev, "failed to init chip support\n");
+ goto fail;
+ }
+
+ host->memmgr = mem_op().alloc_mgr();
+ if (!host->memmgr) {
+ dev_err(&dev->dev, "unable to create nvmap client\n");
+ err = -EIO;
+ goto fail;
+ }
+
+ /* Register host1x device as bus master */
+ host->dev = dev;
+
+ /* Give pointer to host1x via driver */
+ nvhost_set_drvdata(dev, host);
+
+ nvhost_bus_add_host(host);
+
+ err = nvhost_syncpt_init(dev, &host->syncpt);
+ if (err)
+ goto fail;
+
+ err = nvhost_intr_init(&host->intr, intr1->start, intr0->start);
+ if (err)
+ goto fail;
+
+ err = nvhost_user_init(host);
+ if (err)
+ goto fail;
+
+ err = nvhost_module_init(dev);
+ if (err)
+ goto fail;
+
+ for (i = 0; i < host->dev->num_clks; i++)
+ clk_enable(host->dev->clk[i]);
+ nvhost_syncpt_reset(&host->syncpt);
+ for (i = 0; i < host->dev->num_clks; i++)
+ clk_disable(host->dev->clk[0]);
+
+ nvhost_debug_init(host);
+
+ dev_info(&dev->dev, "initialized\n");
+ return 0;
+
+fail:
+ nvhost_free_resources(host);
+ if (host->memmgr)
+ mem_op().put_mgr(host->memmgr);
+ kfree(host);
+ return err;
+}
+
+static int __exit nvhost_remove(struct nvhost_device *dev)
+{
+ struct nvhost_master *host = nvhost_get_drvdata(dev);
+ nvhost_intr_deinit(&host->intr);
+ nvhost_syncpt_deinit(&host->syncpt);
+ nvhost_free_resources(host);
+ return 0;
+}
+
+static int nvhost_suspend(struct nvhost_device *dev, pm_message_t state)
+{
+ struct nvhost_master *host = nvhost_get_drvdata(dev);
+ int ret = 0;
+
+ ret = nvhost_module_suspend(host->dev);
+ dev_info(&dev->dev, "suspend status: %d\n", ret);
+
+ return ret;
+}
+
+static int nvhost_resume(struct nvhost_device *dev)
+{
+ dev_info(&dev->dev, "resuming\n");
+ return 0;
+}
+
+static struct nvhost_driver nvhost_driver = {
+ .probe = nvhost_probe,
+ .remove = __exit_p(nvhost_remove),
+ .suspend = nvhost_suspend,
+ .resume = nvhost_resume,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRIVER_NAME
+ },
+ .finalize_poweron = power_on_host,
+ .prepare_poweroff = power_off_host,
+};
+
+static int __init nvhost_mod_init(void)
+{
+ return nvhost_driver_register(&nvhost_driver);
+}
+
+static void __exit nvhost_mod_exit(void)
+{
+ nvhost_driver_unregister(&nvhost_driver);
+}
+
+/* host1x master device needs nvmap to be instantiated first.
+ * nvmap is instantiated via fs_initcall.
+ * Hence instantiate host1x master device using rootfs_initcall
+ * which is one level after fs_initcall. */
+rootfs_initcall(nvhost_mod_init);
+module_exit(nvhost_mod_exit);
+
diff --git a/drivers/video/tegra/host/host1x/host1x.h b/drivers/video/tegra/host/host1x/host1x.h
new file mode 100644
index 000000000000..49916b0757d4
--- /dev/null
+++ b/drivers/video/tegra/host/host1x/host1x.h
@@ -0,0 +1,78 @@
+/*
+ * drivers/video/tegra/host/host1x/host1x.h
+ *
+ * Tegra Graphics Host Driver Entrypoint
+ *
+ * Copyright (c) 2010-2012, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __NVHOST_HOST1X_H
+#define __NVHOST_HOST1X_H
+
+#include <linux/cdev.h>
+#include <linux/nvhost.h>
+
+#include "nvhost_syncpt.h"
+#include "nvhost_intr.h"
+
+#define TRACE_MAX_LENGTH 128U
+#define IFACE_NAME "nvhost"
+
+struct nvhost_channel;
+struct mem_mgr;
+
+struct host1x_device_info {
+ int nb_channels; /* host1x: num channels supported */
+ int nb_pts; /* host1x: num syncpoints supported */
+ int nb_bases; /* host1x: num syncpoints supported */
+ u32 client_managed; /* host1x: client managed syncpts */
+ int nb_mlocks; /* host1x: number of mlocks */
+ const char **syncpt_names; /* names of sync points */
+};
+
+struct nvhost_master {
+ void __iomem *aperture;
+ void __iomem *sync_aperture;
+ struct resource *reg_mem;
+ struct class *nvhost_class;
+ struct cdev cdev;
+ struct device *ctrl;
+ struct nvhost_syncpt syncpt;
+ struct mem_mgr *memmgr;
+ struct nvhost_intr intr;
+ struct nvhost_device *dev;
+ atomic_t clientid;
+
+ struct host1x_device_info info;
+};
+
+extern struct nvhost_master *nvhost;
+
+void nvhost_debug_init(struct nvhost_master *master);
+void nvhost_debug_dump(struct nvhost_master *master);
+
+struct nvhost_channel *nvhost_alloc_channel(struct nvhost_device *dev);
+void nvhost_free_channel(struct nvhost_channel *ch);
+
+extern pid_t nvhost_debug_null_kickoff_pid;
+
+static inline struct nvhost_master *nvhost_get_host(struct nvhost_device *_dev)
+{
+ return (_dev->dev.parent) ? \
+ ((struct nvhost_master *) dev_get_drvdata(_dev->dev.parent)) : \
+ ((struct nvhost_master *) dev_get_drvdata(&(_dev->dev)));
+}
+
+#endif
diff --git a/drivers/video/tegra/host/host1x/host1x01_hardware.h b/drivers/video/tegra/host/host1x/host1x01_hardware.h
new file mode 100644
index 000000000000..1d30cc74266a
--- /dev/null
+++ b/drivers/video/tegra/host/host1x/host1x01_hardware.h
@@ -0,0 +1,170 @@
+/*
+ * drivers/video/tegra/host/host1x/host1x01_hardware.h
+ *
+ * Tegra Graphics Host Register Offsets for T20/T30
+ *
+ * Copyright (c) 2010-2012 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __NVHOST_HOST1X01_HARDWARE_H
+#define __NVHOST_HOST1X01_HARDWARE_H
+
+#include <linux/types.h>
+#include <linux/bitops.h>
+#include "hw_host1x01_channel.h"
+#include "hw_host1x01_sync.h"
+#include "hw_host1x01_uclass.h"
+
+/* class ids */
+enum {
+ NV_HOST1X_CLASS_ID = 0x1,
+ NV_VIDEO_ENCODE_MPEG_CLASS_ID = 0x20,
+ NV_GRAPHICS_3D_CLASS_ID = 0x60
+};
+
+
+/* channel registers */
+#define NV_HOST1X_CHANNEL_MAP_SIZE_BYTES 16384
+#define NV_HOST1X_SYNC_MLOCK_NUM 16
+
+/* sync registers */
+#define HOST1X_CHANNEL_SYNC_REG_BASE 0x3000
+#define NV_HOST1X_NB_MLOCKS 16
+
+static inline u32 nvhost_class_host_wait_syncpt(
+ unsigned indx, unsigned threshold)
+{
+ return (indx << 24) | (threshold & 0xffffff);
+}
+
+static inline u32 nvhost_class_host_load_syncpt_base(
+ unsigned indx, unsigned threshold)
+{
+ return host1x_uclass_wait_syncpt_indx_f(indx)
+ | host1x_uclass_wait_syncpt_thresh_f(threshold);
+}
+
+static inline u32 nvhost_class_host_wait_syncpt_base(
+ unsigned indx, unsigned base_indx, unsigned offset)
+{
+ return host1x_uclass_wait_syncpt_base_indx_f(indx)
+ | host1x_uclass_wait_syncpt_base_base_indx_f(base_indx)
+ | host1x_uclass_wait_syncpt_base_offset_f(offset);
+}
+
+static inline u32 nvhost_class_host_incr_syncpt_base(
+ unsigned base_indx, unsigned offset)
+{
+ return host1x_uclass_incr_syncpt_base_base_indx_f(base_indx)
+ | host1x_uclass_incr_syncpt_base_offset_f(offset);
+}
+
+static inline u32 nvhost_class_host_incr_syncpt(
+ unsigned cond, unsigned indx)
+{
+ return host1x_uclass_incr_syncpt_cond_f(cond)
+ | host1x_uclass_incr_syncpt_indx_f(indx);
+}
+
+enum {
+ NV_HOST_MODULE_HOST1X = 0,
+ NV_HOST_MODULE_MPE = 1,
+ NV_HOST_MODULE_GR3D = 6
+};
+
+static inline u32 nvhost_class_host_indoff_reg_write(
+ unsigned mod_id, unsigned offset, bool auto_inc)
+{
+ u32 v = host1x_uclass_indoff_indbe_f(0xf)
+ | host1x_uclass_indoff_indmodid_f(mod_id)
+ | host1x_uclass_indoff_indroffset_f(offset);
+ if (auto_inc)
+ v |= host1x_uclass_indoff_autoinc_f(1);
+ return v;
+}
+
+static inline u32 nvhost_class_host_indoff_reg_read(
+ unsigned mod_id, unsigned offset, bool auto_inc)
+{
+ u32 v = host1x_uclass_indoff_indmodid_f(mod_id)
+ | host1x_uclass_indoff_indroffset_f(offset)
+ | host1x_uclass_indoff_rwn_read_v();
+ if (auto_inc)
+ v |= host1x_uclass_indoff_autoinc_f(1);
+ return v;
+}
+
+
+/* cdma opcodes */
+static inline u32 nvhost_opcode_setclass(
+ unsigned class_id, unsigned offset, unsigned mask)
+{
+ return (0 << 28) | (offset << 16) | (class_id << 6) | mask;
+}
+
+static inline u32 nvhost_opcode_incr(unsigned offset, unsigned count)
+{
+ return (1 << 28) | (offset << 16) | count;
+}
+
+static inline u32 nvhost_opcode_nonincr(unsigned offset, unsigned count)
+{
+ return (2 << 28) | (offset << 16) | count;
+}
+
+static inline u32 nvhost_opcode_mask(unsigned offset, unsigned mask)
+{
+ return (3 << 28) | (offset << 16) | mask;
+}
+
+static inline u32 nvhost_opcode_imm(unsigned offset, unsigned value)
+{
+ return (4 << 28) | (offset << 16) | value;
+}
+
+static inline u32 nvhost_opcode_imm_incr_syncpt(unsigned cond, unsigned indx)
+{
+ return nvhost_opcode_imm(host1x_uclass_incr_syncpt_r(),
+ nvhost_class_host_incr_syncpt(cond, indx));
+}
+
+static inline u32 nvhost_opcode_restart(unsigned address)
+{
+ return (5 << 28) | (address >> 4);
+}
+
+static inline u32 nvhost_opcode_gather(unsigned count)
+{
+ return (6 << 28) | count;
+}
+
+static inline u32 nvhost_opcode_gather_nonincr(unsigned offset, unsigned count)
+{
+ return (6 << 28) | (offset << 16) | BIT(15) | count;
+}
+
+static inline u32 nvhost_opcode_gather_incr(unsigned offset, unsigned count)
+{
+ return (6 << 28) | (offset << 16) | BIT(15) | BIT(14) | count;
+}
+
+#define NVHOST_OPCODE_NOOP nvhost_opcode_nonincr(0, 0)
+
+static inline u32 nvhost_mask2(unsigned x, unsigned y)
+{
+ return 1 | (1 << (y - x));
+}
+
+#endif
diff --git a/drivers/video/tegra/host/host1x/host1x_cdma.c b/drivers/video/tegra/host/host1x/host1x_cdma.c
index cdd6026718b1..2e7ff5783a37 100644
--- a/drivers/video/tegra/host/host1x/host1x_cdma.c
+++ b/drivers/video/tegra/host/host1x/host1x_cdma.c
@@ -19,19 +19,21 @@
*/
#include <linux/slab.h>
+#include "nvhost_acm.h"
#include "nvhost_cdma.h"
+#include "nvhost_channel.h"
#include "dev.h"
+#include "chip_support.h"
+#include "nvhost_memmgr.h"
-#include "host1x_hardware.h"
-#include "host1x_syncpt.h"
#include "host1x_cdma.h"
#include "host1x_hwctx.h"
static inline u32 host1x_channel_dmactrl(int stop, int get_rst, int init_get)
{
- return HOST1X_CREATE(CHANNEL_DMACTRL, DMASTOP, stop)
- | HOST1X_CREATE(CHANNEL_DMACTRL, DMAGETRST, get_rst)
- | HOST1X_CREATE(CHANNEL_DMACTRL, DMAINITGET, init_get);
+ return host1x_channel_dmactrl_dmastop_f(stop)
+ | host1x_channel_dmactrl_dmagetrst_f(get_rst)
+ | host1x_channel_dmactrl_dmainitget_f(init_get);
}
static void cdma_timeout_handler(struct work_struct *work);
@@ -60,38 +62,38 @@ static void push_buffer_reset(struct push_buffer *pb)
static int push_buffer_init(struct push_buffer *pb)
{
struct nvhost_cdma *cdma = pb_to_cdma(pb);
- struct nvmap_client *nvmap = cdma_to_nvmap(cdma);
+ struct mem_mgr *mgr = cdma_to_memmgr(cdma);
pb->mem = NULL;
pb->mapped = NULL;
pb->phys = 0;
- pb->nvmap = NULL;
+ pb->client_handle = NULL;
- BUG_ON(!cdma_pb_op(cdma).reset);
- cdma_pb_op(cdma).reset(pb);
+ BUG_ON(!cdma_pb_op().reset);
+ cdma_pb_op().reset(pb);
/* allocate and map pushbuffer memory */
- pb->mem = nvmap_alloc(nvmap, PUSH_BUFFER_SIZE + 4, 32,
- NVMAP_HANDLE_WRITE_COMBINE, 0);
+ pb->mem = mem_op().alloc(mgr, PUSH_BUFFER_SIZE + 4, 32,
+ mem_mgr_flag_write_combine);
if (IS_ERR_OR_NULL(pb->mem)) {
pb->mem = NULL;
goto fail;
}
- pb->mapped = nvmap_mmap(pb->mem);
+ pb->mapped = mem_op().mmap(pb->mem);
if (pb->mapped == NULL)
goto fail;
/* pin pushbuffer and get physical address */
- pb->phys = nvmap_pin(nvmap, pb->mem);
+ pb->phys = mem_op().pin(mgr, pb->mem);
if (pb->phys >= 0xfffff000) {
pb->phys = 0;
goto fail;
}
/* memory for storing nvmap client and handles for each opcode pair */
- pb->nvmap = kzalloc(NVHOST_GATHER_QUEUE_SIZE *
- sizeof(struct nvmap_client_handle),
+ pb->client_handle = kzalloc(NVHOST_GATHER_QUEUE_SIZE *
+ sizeof(struct mem_mgr_handle),
GFP_KERNEL);
- if (!pb->nvmap)
+ if (!pb->client_handle)
goto fail;
/* put the restart at the end of pushbuffer memory */
@@ -101,7 +103,7 @@ static int push_buffer_init(struct push_buffer *pb)
return 0;
fail:
- cdma_pb_op(cdma).destroy(pb);
+ cdma_pb_op().destroy(pb);
return -ENOMEM;
}
@@ -111,22 +113,22 @@ fail:
static void push_buffer_destroy(struct push_buffer *pb)
{
struct nvhost_cdma *cdma = pb_to_cdma(pb);
- struct nvmap_client *nvmap = cdma_to_nvmap(cdma);
+ struct mem_mgr *mgr = cdma_to_memmgr(cdma);
if (pb->mapped)
- nvmap_munmap(pb->mem, pb->mapped);
+ mem_op().munmap(pb->mem, pb->mapped);
if (pb->phys != 0)
- nvmap_unpin(nvmap, pb->mem);
+ mem_op().unpin(mgr, pb->mem);
if (pb->mem)
- nvmap_free(nvmap, pb->mem);
+ mem_op().put(mgr, pb->mem);
- kfree(pb->nvmap);
+ kfree(pb->client_handle);
pb->mem = NULL;
pb->mapped = NULL;
pb->phys = 0;
- pb->nvmap = 0;
+ pb->client_handle = 0;
}
/**
@@ -134,8 +136,8 @@ static void push_buffer_destroy(struct push_buffer *pb)
* Caller must ensure push buffer is not full
*/
static void push_buffer_push_to(struct push_buffer *pb,
- struct nvmap_client *client,
- struct nvmap_handle *handle, u32 op1, u32 op2)
+ struct mem_mgr *client, struct mem_handle *handle,
+ u32 op1, u32 op2)
{
u32 cur = pb->cur;
u32 *p = (u32 *)((u32)pb->mapped + cur);
@@ -143,8 +145,8 @@ static void push_buffer_push_to(struct push_buffer *pb,
BUG_ON(cur == pb->fence);
*(p++) = op1;
*(p++) = op2;
- pb->nvmap[cur_nvmap].client = client;
- pb->nvmap[cur_nvmap].handle = handle;
+ pb->client_handle[cur_nvmap].client = client;
+ pb->client_handle[cur_nvmap].handle = handle;
pb->cur = (cur + 8) & (PUSH_BUFFER_SIZE - 1);
}
@@ -161,8 +163,7 @@ static void push_buffer_pop_from(struct push_buffer *pb,
for (i = 0; i < slots; i++) {
int cur_fence_nvmap = (fence_nvmap+i)
& (NVHOST_GATHER_QUEUE_SIZE - 1);
- struct nvmap_client_handle *h =
- &pb->nvmap[cur_fence_nvmap];
+ struct mem_mgr_handle *h = &pb->client_handle[cur_fence_nvmap];
h->client = NULL;
h->handle = NULL;
}
@@ -191,96 +192,25 @@ static u32 push_buffer_putptr(struct push_buffer *pb)
*/
/**
- * Init timeout and syncpt incr buffer resources
+ * Init timeout resources
*/
static int cdma_timeout_init(struct nvhost_cdma *cdma,
u32 syncpt_id)
{
- struct nvhost_master *dev = cdma_to_dev(cdma);
- struct nvmap_client *nvmap = cdma_to_nvmap(cdma);
- struct syncpt_buffer *sb = &cdma->syncpt_buffer;
- struct nvhost_channel *ch = cdma_to_channel(cdma);
- u32 i = 0;
-
if (syncpt_id == NVSYNCPT_INVALID)
return -EINVAL;
- /* allocate and map syncpt incr memory */
- sb->mem = nvmap_alloc(nvmap,
- (SYNCPT_INCR_BUFFER_SIZE_WORDS * sizeof(u32)), 32,
- NVMAP_HANDLE_WRITE_COMBINE, 0);
- if (IS_ERR_OR_NULL(sb->mem)) {
- sb->mem = NULL;
- goto fail;
- }
- sb->mapped = nvmap_mmap(sb->mem);
- if (sb->mapped == NULL)
- goto fail;
-
- /* pin syncpt buffer and get physical address */
- sb->phys = nvmap_pin(nvmap, sb->mem);
- if (sb->phys >= 0xfffff000) {
- sb->phys = 0;
- goto fail;
- }
-
- dev_dbg(&dev->dev->dev, "%s: SYNCPT_INCR buffer at 0x%x\n",
- __func__, sb->phys);
-
- sb->words_per_incr = (syncpt_id == NVSYNCPT_3D) ? 5 : 3;
- sb->incr_per_buffer = (SYNCPT_INCR_BUFFER_SIZE_WORDS /
- sb->words_per_incr);
-
- /* init buffer with SETCL and INCR_SYNCPT methods */
- while (i < sb->incr_per_buffer) {
- sb->mapped[i++] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
- 0, 0);
- sb->mapped[i++] = nvhost_opcode_imm_incr_syncpt(
- NV_SYNCPT_IMMEDIATE,
- syncpt_id);
- if (syncpt_id == NVSYNCPT_3D) {
- /* also contains base increments */
- sb->mapped[i++] = nvhost_opcode_nonincr(
- NV_CLASS_HOST_INCR_SYNCPT_BASE,
- 1);
- sb->mapped[i++] = nvhost_class_host_incr_syncpt_base(
- NVWAITBASE_3D, 1);
- }
- sb->mapped[i++] = nvhost_opcode_setclass(ch->dev->class,
- 0, 0);
- }
- wmb();
-
INIT_DELAYED_WORK(&cdma->timeout.wq, cdma_timeout_handler);
cdma->timeout.initialized = true;
return 0;
-fail:
- cdma_op(cdma).timeout_destroy(cdma);
- return -ENOMEM;
}
/**
- * Clean up timeout syncpt buffer resources
+ * Clean up timeout resources
*/
static void cdma_timeout_destroy(struct nvhost_cdma *cdma)
{
- struct nvmap_client *nvmap = cdma_to_nvmap(cdma);
- struct syncpt_buffer *sb = &cdma->syncpt_buffer;
-
- if (sb->mapped)
- nvmap_munmap(sb->mem, sb->mapped);
-
- if (sb->phys != 0)
- nvmap_unpin(nvmap, sb->mem);
-
- if (sb->mem)
- nvmap_free(nvmap, sb->mem);
-
- sb->mem = NULL;
- sb->mapped = NULL;
- sb->phys = 0;
-
if (cdma->timeout.initialized)
cancel_delayed_work(&cdma->timeout.wq);
cdma->timeout.initialized = false;
@@ -290,7 +220,8 @@ static void cdma_timeout_destroy(struct nvhost_cdma *cdma)
* Increment timedout buffer's syncpt via CPU.
*/
static void cdma_timeout_cpu_incr(struct nvhost_cdma *cdma, u32 getptr,
- u32 syncpt_incrs, u32 syncval, u32 nr_slots)
+ u32 syncpt_incrs, u32 syncval, u32 nr_slots,
+ u32 waitbases)
{
struct nvhost_master *dev = cdma_to_dev(cdma);
struct push_buffer *pb = &cdma->push_buffer;
@@ -303,10 +234,10 @@ static void cdma_timeout_cpu_incr(struct nvhost_cdma *cdma, u32 getptr,
nvhost_syncpt_update_min(&dev->syncpt, cdma->timeout.syncpt_id);
/* update WAITBASE_3D by same number of incrs */
- if (cdma->timeout.syncpt_id == NVSYNCPT_3D) {
+ if (waitbases) {
void __iomem *p;
- p = dev->sync_aperture + HOST1X_SYNC_SYNCPT_BASE_0 +
- (NVWAITBASE_3D * sizeof(u32));
+ p = dev->sync_aperture + host1x_sync_syncpt_base_0_r() +
+ (ffs(waitbases) * sizeof(u32));
writel(syncval, p);
}
@@ -324,73 +255,6 @@ static void cdma_timeout_cpu_incr(struct nvhost_cdma *cdma, u32 getptr,
}
/**
- * This routine is called at the point we transition back into a timed
- * ctx. The syncpts are incremented via pushbuffer with a flag indicating
- * whether there's a CTXSAVE that should be still executed (for the
- * preceding HW ctx).
- */
-static void cdma_timeout_pb_incr(struct nvhost_cdma *cdma, u32 getptr,
- u32 syncpt_incrs, u32 nr_slots,
- bool exec_ctxsave)
-{
- struct nvhost_master *dev = cdma_to_dev(cdma);
- struct syncpt_buffer *sb = &cdma->syncpt_buffer;
- struct push_buffer *pb = &cdma->push_buffer;
- struct host1x_hwctx *hwctx = to_host1x_hwctx(cdma->timeout.ctx);
- u32 getidx, *p;
-
- /* should have enough slots to incr to desired count */
- BUG_ON(syncpt_incrs > (nr_slots * sb->incr_per_buffer));
-
- getidx = getptr - pb->phys;
- if (exec_ctxsave) {
- /* don't disrupt the CTXSAVE of a good/non-timed out ctx */
- nr_slots -= hwctx->save_slots;
- syncpt_incrs -= hwctx->save_incrs;
-
- getidx += (hwctx->save_slots * 8);
- getidx &= (PUSH_BUFFER_SIZE - 1);
-
- dev_dbg(&dev->dev->dev,
- "%s: exec CTXSAVE of prev ctx (slots %d, incrs %d)\n",
- __func__, nr_slots, syncpt_incrs);
- }
-
- while (syncpt_incrs) {
- u32 incrs, count;
-
- /* GATHER count are incrs * number of DWORDs per incr */
- incrs = min(syncpt_incrs, sb->incr_per_buffer);
- count = incrs * sb->words_per_incr;
-
- p = (u32 *)((u32)pb->mapped + getidx);
- *(p++) = nvhost_opcode_gather(count);
- *(p++) = sb->phys;
-
- dev_dbg(&dev->dev->dev,
- "%s: GATHER at 0x%x, from 0x%x, dcount = %d\n",
- __func__,
- pb->phys + getidx, sb->phys,
- (incrs * sb->words_per_incr));
-
- syncpt_incrs -= incrs;
- getidx = (getidx + 8) & (PUSH_BUFFER_SIZE - 1);
- nr_slots--;
- }
-
- /* NOP remaining slots */
- while (nr_slots--) {
- p = (u32 *)((u32)pb->mapped + getidx);
- *(p++) = NVHOST_OPCODE_NOOP;
- *(p++) = NVHOST_OPCODE_NOOP;
- dev_dbg(&dev->dev->dev, "%s: NOP at 0x%x\n",
- __func__, pb->phys + getidx);
- getidx = (getidx + 8) & (PUSH_BUFFER_SIZE - 1);
- }
- wmb();
-}
-
-/**
* Start channel DMA
*/
static void cdma_start(struct nvhost_cdma *cdma)
@@ -400,24 +264,24 @@ static void cdma_start(struct nvhost_cdma *cdma)
if (cdma->running)
return;
- BUG_ON(!cdma_pb_op(cdma).putptr);
- cdma->last_put = cdma_pb_op(cdma).putptr(&cdma->push_buffer);
+ BUG_ON(!cdma_pb_op().putptr);
+ cdma->last_put = cdma_pb_op().putptr(&cdma->push_buffer);
writel(host1x_channel_dmactrl(true, false, false),
- chan_regs + HOST1X_CHANNEL_DMACTRL);
+ chan_regs + host1x_channel_dmactrl_r());
/* set base, put, end pointer (all of memory) */
- writel(0, chan_regs + HOST1X_CHANNEL_DMASTART);
- writel(cdma->last_put, chan_regs + HOST1X_CHANNEL_DMAPUT);
- writel(0xFFFFFFFF, chan_regs + HOST1X_CHANNEL_DMAEND);
+ writel(0, chan_regs + host1x_channel_dmastart_r());
+ writel(cdma->last_put, chan_regs + host1x_channel_dmaput_r());
+ writel(0xFFFFFFFF, chan_regs + host1x_channel_dmaend_r());
/* reset GET */
writel(host1x_channel_dmactrl(true, true, true),
- chan_regs + HOST1X_CHANNEL_DMACTRL);
+ chan_regs + host1x_channel_dmactrl_r());
/* start the command DMA */
writel(host1x_channel_dmactrl(false, false, false),
- chan_regs + HOST1X_CHANNEL_DMACTRL);
+ chan_regs + host1x_channel_dmactrl_r());
cdma->running = true;
}
@@ -435,36 +299,36 @@ static void cdma_timeout_restart(struct nvhost_cdma *cdma, u32 getptr)
if (cdma->running)
return;
- BUG_ON(!cdma_pb_op(cdma).putptr);
- cdma->last_put = cdma_pb_op(cdma).putptr(&cdma->push_buffer);
+ BUG_ON(!cdma_pb_op().putptr);
+ cdma->last_put = cdma_pb_op().putptr(&cdma->push_buffer);
writel(host1x_channel_dmactrl(true, false, false),
- chan_regs + HOST1X_CHANNEL_DMACTRL);
+ chan_regs + host1x_channel_dmactrl_r());
/* set base, end pointer (all of memory) */
- writel(0, chan_regs + HOST1X_CHANNEL_DMASTART);
- writel(0xFFFFFFFF, chan_regs + HOST1X_CHANNEL_DMAEND);
+ writel(0, chan_regs + host1x_channel_dmastart_r());
+ writel(0xFFFFFFFF, chan_regs + host1x_channel_dmaend_r());
/* set GET, by loading the value in PUT (then reset GET) */
- writel(getptr, chan_regs + HOST1X_CHANNEL_DMAPUT);
+ writel(getptr, chan_regs + host1x_channel_dmaput_r());
writel(host1x_channel_dmactrl(true, true, true),
- chan_regs + HOST1X_CHANNEL_DMACTRL);
+ chan_regs + host1x_channel_dmactrl_r());
dev_dbg(&dev->dev->dev,
"%s: DMA GET 0x%x, PUT HW 0x%x / shadow 0x%x\n",
__func__,
- readl(chan_regs + HOST1X_CHANNEL_DMAGET),
- readl(chan_regs + HOST1X_CHANNEL_DMAPUT),
+ readl(chan_regs + host1x_channel_dmaget_r()),
+ readl(chan_regs + host1x_channel_dmaput_r()),
cdma->last_put);
/* deassert GET reset and set PUT */
writel(host1x_channel_dmactrl(true, false, false),
- chan_regs + HOST1X_CHANNEL_DMACTRL);
- writel(cdma->last_put, chan_regs + HOST1X_CHANNEL_DMAPUT);
+ chan_regs + host1x_channel_dmactrl_r());
+ writel(cdma->last_put, chan_regs + host1x_channel_dmaput_r());
/* start the command DMA */
writel(host1x_channel_dmactrl(false, false, false),
- chan_regs + HOST1X_CHANNEL_DMACTRL);
+ chan_regs + host1x_channel_dmactrl_r());
cdma->running = true;
}
@@ -475,14 +339,14 @@ static void cdma_timeout_restart(struct nvhost_cdma *cdma, u32 getptr)
static void cdma_kick(struct nvhost_cdma *cdma)
{
u32 put;
- BUG_ON(!cdma_pb_op(cdma).putptr);
+ BUG_ON(!cdma_pb_op().putptr);
- put = cdma_pb_op(cdma).putptr(&cdma->push_buffer);
+ put = cdma_pb_op().putptr(&cdma->push_buffer);
if (put != cdma->last_put) {
void __iomem *chan_regs = cdma_to_channel(cdma)->aperture;
wmb();
- writel(put, chan_regs + HOST1X_CHANNEL_DMAPUT);
+ writel(put, chan_regs + host1x_channel_dmaput_r());
cdma->last_put = put;
}
}
@@ -495,31 +359,17 @@ static void cdma_stop(struct nvhost_cdma *cdma)
if (cdma->running) {
nvhost_cdma_wait_locked(cdma, CDMA_EVENT_SYNC_QUEUE_EMPTY);
writel(host1x_channel_dmactrl(true, false, false),
- chan_regs + HOST1X_CHANNEL_DMACTRL);
+ chan_regs + host1x_channel_dmactrl_r());
cdma->running = false;
}
mutex_unlock(&cdma->lock);
}
/**
- * Retrieve the op pair at a slot offset from a DMA address
- */
-void cdma_peek(struct nvhost_cdma *cdma,
- u32 dmaget, int slot, u32 *out)
-{
- u32 offset = dmaget - cdma->push_buffer.phys;
- u32 *p = cdma->push_buffer.mapped;
-
- offset = ((offset + slot * 8) & (PUSH_BUFFER_SIZE - 1)) >> 2;
- out[0] = p[offset];
- out[1] = p[offset + 1];
-}
-
-/**
* Stops both channel's command processor and CDMA immediately.
* Also, tears down the channel and resets corresponding module.
*/
-void cdma_timeout_teardown_begin(struct nvhost_cdma *cdma)
+static void cdma_timeout_teardown_begin(struct nvhost_cdma *cdma)
{
struct nvhost_master *dev = cdma_to_dev(cdma);
struct nvhost_channel *ch = cdma_to_channel(cdma);
@@ -530,28 +380,28 @@ void cdma_timeout_teardown_begin(struct nvhost_cdma *cdma)
dev_dbg(&dev->dev->dev,
"begin channel teardown (channel id %d)\n", ch->chid);
- cmdproc_stop = readl(dev->sync_aperture + HOST1X_SYNC_CMDPROC_STOP);
+ cmdproc_stop = readl(dev->sync_aperture + host1x_sync_cmdproc_stop_r());
cmdproc_stop |= BIT(ch->chid);
- writel(cmdproc_stop, dev->sync_aperture + HOST1X_SYNC_CMDPROC_STOP);
+ writel(cmdproc_stop, dev->sync_aperture + host1x_sync_cmdproc_stop_r());
dev_dbg(&dev->dev->dev,
"%s: DMA GET 0x%x, PUT HW 0x%x / shadow 0x%x\n",
__func__,
- readl(ch->aperture + HOST1X_CHANNEL_DMAGET),
- readl(ch->aperture + HOST1X_CHANNEL_DMAPUT),
+ readl(ch->aperture + host1x_channel_dmaget_r()),
+ readl(ch->aperture + host1x_channel_dmaput_r()),
cdma->last_put);
writel(host1x_channel_dmactrl(true, false, false),
- ch->aperture + HOST1X_CHANNEL_DMACTRL);
+ ch->aperture + host1x_channel_dmactrl_r());
- writel(BIT(ch->chid), dev->sync_aperture + HOST1X_SYNC_CH_TEARDOWN);
+ writel(BIT(ch->chid), dev->sync_aperture + host1x_sync_ch_teardown_r());
nvhost_module_reset(ch->dev);
cdma->running = false;
cdma->torndown = true;
}
-void cdma_timeout_teardown_end(struct nvhost_cdma *cdma, u32 getptr)
+static void cdma_timeout_teardown_end(struct nvhost_cdma *cdma, u32 getptr)
{
struct nvhost_master *dev = cdma_to_dev(cdma);
struct nvhost_channel *ch = cdma_to_channel(cdma);
@@ -563,9 +413,9 @@ void cdma_timeout_teardown_end(struct nvhost_cdma *cdma, u32 getptr)
"end channel teardown (id %d, DMAGET restart = 0x%x)\n",
ch->chid, getptr);
- cmdproc_stop = readl(dev->sync_aperture + HOST1X_SYNC_CMDPROC_STOP);
+ cmdproc_stop = readl(dev->sync_aperture + host1x_sync_cmdproc_stop_r());
cmdproc_stop &= ~(BIT(ch->chid));
- writel(cmdproc_stop, dev->sync_aperture + HOST1X_SYNC_CMDPROC_STOP);
+ writel(cmdproc_stop, dev->sync_aperture + host1x_sync_cmdproc_stop_r());
cdma->torndown = false;
cdma_timeout_restart(cdma, getptr);
@@ -603,9 +453,9 @@ static void cdma_timeout_handler(struct work_struct *work)
}
/* stop processing to get a clean snapshot */
- prev_cmdproc = readl(dev->sync_aperture + HOST1X_SYNC_CMDPROC_STOP);
+ prev_cmdproc = readl(dev->sync_aperture + host1x_sync_cmdproc_stop_r());
cmdproc_stop = prev_cmdproc | BIT(ch->chid);
- writel(cmdproc_stop, dev->sync_aperture + HOST1X_SYNC_CMDPROC_STOP);
+ writel(cmdproc_stop, dev->sync_aperture + host1x_sync_cmdproc_stop_r());
dev_dbg(&dev->dev->dev, "cdma_timeout: cmdproc was 0x%x is 0x%x\n",
prev_cmdproc, cmdproc_stop);
@@ -620,7 +470,7 @@ static void cdma_timeout_handler(struct work_struct *work)
/* restore */
cmdproc_stop = prev_cmdproc & ~(BIT(ch->chid));
writel(cmdproc_stop,
- dev->sync_aperture + HOST1X_SYNC_CMDPROC_STOP);
+ dev->sync_aperture + host1x_sync_cmdproc_stop_r());
mutex_unlock(&cdma->lock);
return;
}
@@ -629,37 +479,36 @@ static void cdma_timeout_handler(struct work_struct *work)
"%s: timeout: %d (%s) ctx 0x%p, HW thresh %d, done %d\n",
__func__,
cdma->timeout.syncpt_id,
- syncpt_op(sp).name(sp, cdma->timeout.syncpt_id),
+ syncpt_op().name(sp, cdma->timeout.syncpt_id),
cdma->timeout.ctx,
syncpt_val, cdma->timeout.syncpt_val);
/* stop HW, resetting channel/module */
- cdma_op(cdma).timeout_teardown_begin(cdma);
+ cdma_op().timeout_teardown_begin(cdma);
- nvhost_cdma_update_sync_queue(cdma, sp, &dev->dev->dev);
+ nvhost_cdma_update_sync_queue(cdma, sp, dev->dev);
mutex_unlock(&cdma->lock);
}
-int host1x_init_cdma_support(struct nvhost_master *host)
-{
- host->op.cdma.start = cdma_start;
- host->op.cdma.stop = cdma_stop;
- host->op.cdma.kick = cdma_kick;
-
- host->op.cdma.timeout_init = cdma_timeout_init;
- host->op.cdma.timeout_destroy = cdma_timeout_destroy;
- host->op.cdma.timeout_teardown_begin = cdma_timeout_teardown_begin;
- host->op.cdma.timeout_teardown_end = cdma_timeout_teardown_end;
- host->op.cdma.timeout_cpu_incr = cdma_timeout_cpu_incr;
- host->op.cdma.timeout_pb_incr = cdma_timeout_pb_incr;
-
- host->op.push_buffer.reset = push_buffer_reset;
- host->op.push_buffer.init = push_buffer_init;
- host->op.push_buffer.destroy = push_buffer_destroy;
- host->op.push_buffer.push_to = push_buffer_push_to;
- host->op.push_buffer.pop_from = push_buffer_pop_from;
- host->op.push_buffer.space = push_buffer_space;
- host->op.push_buffer.putptr = push_buffer_putptr;
+static const struct nvhost_cdma_ops host1x_cdma_ops = {
+ .start = cdma_start,
+ .stop = cdma_stop,
+ .kick = cdma_kick,
+
+ .timeout_init = cdma_timeout_init,
+ .timeout_destroy = cdma_timeout_destroy,
+ .timeout_teardown_begin = cdma_timeout_teardown_begin,
+ .timeout_teardown_end = cdma_timeout_teardown_end,
+ .timeout_cpu_incr = cdma_timeout_cpu_incr,
+};
+
+static const struct nvhost_pushbuffer_ops host1x_pushbuffer_ops = {
+ .reset = push_buffer_reset,
+ .init = push_buffer_init,
+ .destroy = push_buffer_destroy,
+ .push_to = push_buffer_push_to,
+ .pop_from = push_buffer_pop_from,
+ .space = push_buffer_space,
+ .putptr = push_buffer_putptr,
+};
- return 0;
-}
diff --git a/drivers/video/tegra/host/host1x/host1x_cdma.h b/drivers/video/tegra/host/host1x/host1x_cdma.h
index 60909236a7ca..94bfc092c8c9 100644
--- a/drivers/video/tegra/host/host1x/host1x_cdma.h
+++ b/drivers/video/tegra/host/host1x/host1x_cdma.h
@@ -1,7 +1,7 @@
/*
* drivers/video/tegra/host/host1x/host1x_cdma.h
*
- * Tegra Graphics Host Channel
+ * Tegra Graphics Host Command DMA
*
* Copyright (c) 2011-2012, NVIDIA Corporation.
*
@@ -36,6 +36,4 @@
* and replaces the original timed out contexts GATHER slots */
#define SYNCPT_INCR_BUFFER_SIZE_WORDS (4096 / sizeof(u32))
-int host1x_init_cdma_support(struct nvhost_master *);
-
#endif
diff --git a/drivers/video/tegra/host/host1x/host1x_channel.c b/drivers/video/tegra/host/host1x/host1x_channel.c
index b16a34f416ab..9e9fc25dc966 100644
--- a/drivers/video/tegra/host/host1x/host1x_channel.c
+++ b/drivers/video/tegra/host/host1x/host1x_channel.c
@@ -20,18 +20,20 @@
#include "nvhost_channel.h"
#include "dev.h"
+#include "nvhost_acm.h"
+#include "nvhost_job.h"
#include "nvhost_hwctx.h"
#include <trace/events/nvhost.h>
#include <linux/slab.h>
-#include "host1x_syncpt.h"
-#include "host1x_channel.h"
-#include "host1x_hardware.h"
#include "host1x_hwctx.h"
#include "nvhost_intr.h"
#define NV_FIFO_READ_TIMEOUT 200000
+static int host1x_drain_read_fifo(struct nvhost_channel *ch,
+ u32 *ptr, unsigned int count, unsigned int *pending);
+
static void sync_waitbases(struct nvhost_channel *ch, u32 syncpt_val)
{
unsigned long waitbase;
@@ -40,7 +42,7 @@ static void sync_waitbases(struct nvhost_channel *ch, u32 syncpt_val)
waitbase = find_first_bit(&waitbase_mask, BITS_PER_LONG);
nvhost_cdma_push(&ch->cdma,
nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
- NV_CLASS_HOST_LOAD_SYNCPT_BASE,
+ host1x_uclass_load_syncpt_base_r(),
1),
nvhost_class_host_load_syncpt_base(waitbase,
syncpt_val));
@@ -140,22 +142,24 @@ static void submit_ctxrestore(struct nvhost_job *job)
/* Send restore buffer to channel */
nvhost_cdma_push_gather(&ch->cdma,
- host->nvmap,
- nvmap_ref_to_handle(ctx->restore),
+ host->memmgr,
+ ctx->restore,
+ 0,
nvhost_opcode_gather(ctx->restore_size),
ctx->restore_phys);
trace_nvhost_channel_context_restore(ch->dev->name, &ctx->hwctx);
}
-void submit_nullkickoff(struct nvhost_job *job, int user_syncpt_incrs)
+static void submit_nullkickoff(struct nvhost_job *job, int user_syncpt_incrs)
{
struct nvhost_channel *ch = job->ch;
int incr;
u32 op_incr;
/* push increments that correspond to nulled out commands */
- op_incr = nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_OP_DONE,
+ op_incr = nvhost_opcode_imm_incr_syncpt(
+ host1x_uclass_incr_syncpt_cond_op_done_v(),
job->syncpt_id);
for (incr = 0; incr < (user_syncpt_incrs >> 1); incr++)
nvhost_cdma_push(&ch->cdma, op_incr, op_incr);
@@ -168,7 +172,7 @@ void submit_nullkickoff(struct nvhost_job *job, int user_syncpt_incrs)
nvhost_cdma_push(&ch->cdma,
nvhost_opcode_setclass(
NV_HOST1X_CLASS_ID,
- NV_CLASS_HOST_INCR_SYNCPT_BASE,
+ host1x_uclass_incr_syncpt_base_r(),
1),
nvhost_class_host_incr_syncpt_base(
waitbase,
@@ -176,20 +180,22 @@ void submit_nullkickoff(struct nvhost_job *job, int user_syncpt_incrs)
}
}
-void submit_gathers(struct nvhost_job *job)
+static void submit_gathers(struct nvhost_job *job)
{
/* push user gathers */
- int i = 0;
- for ( ; i < job->num_gathers; i++) {
+ int i;
+ for (i = 0 ; i < job->num_gathers; i++) {
u32 op1 = nvhost_opcode_gather(job->gathers[i].words);
u32 op2 = job->gathers[i].mem;
nvhost_cdma_push_gather(&job->ch->cdma,
- job->nvmap, job->unpins[i/2],
+ job->memmgr,
+ job->gathers[i].ref,
+ job->gathers[i].offset,
op1, op2);
}
}
-int host1x_channel_submit(struct nvhost_job *job)
+static int host1x_channel_submit(struct nvhost_job *job)
{
struct nvhost_channel *ch = job->ch;
struct nvhost_syncpt *sp = &nvhost_get_host(job->ch->dev)->syncpt;
@@ -198,6 +204,7 @@ int host1x_channel_submit(struct nvhost_job *job)
u32 syncval;
int err;
void *completed_waiter = NULL, *ctxsave_waiter = NULL;
+ struct nvhost_driver *drv = to_nvhost_driver(ch->dev->dev.driver);
/* Bail out on timed out contexts */
if (job->hwctx && job->hwctx->has_timedout)
@@ -205,8 +212,8 @@ int host1x_channel_submit(struct nvhost_job *job)
/* Turn on the client module and host1x */
nvhost_module_busy(ch->dev);
- if (ch->dev->busy)
- ch->dev->busy(ch->dev);
+ if (drv->busy)
+ drv->busy(ch->dev);
/* before error checks, return current max */
prev_max = job->syncpt_end =
@@ -236,22 +243,6 @@ int host1x_channel_submit(struct nvhost_job *job)
goto error;
}
- /* remove stale waits */
- if (job->num_waitchk) {
- err = nvhost_syncpt_wait_check(sp,
- job->nvmap,
- job->waitchk_mask,
- job->waitchk,
- job->num_waitchk);
- if (err) {
- dev_warn(&ch->dev->dev,
- "nvhost_syncpt_wait_check failed: %d\n", err);
- mutex_unlock(&ch->submitlock);
- nvhost_module_idle(ch->dev);
- goto error;
- }
- }
-
/* begin a CDMA submit */
err = nvhost_cdma_begin(&ch->cdma, job);
if (err) {
@@ -260,6 +251,18 @@ int host1x_channel_submit(struct nvhost_job *job)
goto error;
}
+ if (ch->dev->serialize) {
+ /* Force serialization by inserting a host wait for the
+ * previous job to finish before this one can commence. */
+ nvhost_cdma_push(&ch->cdma,
+ nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
+ host1x_uclass_wait_syncpt_r(),
+ 1),
+ nvhost_class_host_wait_syncpt(job->syncpt_id,
+ nvhost_syncpt_read_max(sp,
+ job->syncpt_id)));
+ }
+
submit_ctxsave(job, ctxsave_waiter, ch->cur_ctx);
submit_ctxrestore(job);
ch->cur_ctx = job->hwctx;
@@ -307,7 +310,7 @@ error:
return err;
}
-int host1x_channel_read_3d_reg(
+static int host1x_channel_read_3d_reg(
struct nvhost_channel *channel,
struct nvhost_hwctx *hwctx,
u32 offset,
@@ -339,7 +342,7 @@ int host1x_channel_read_3d_reg(
job = nvhost_job_alloc(channel, hwctx,
NULL,
- nvhost_get_host(channel->dev)->nvmap, 0, 0);
+ nvhost_get_host(channel->dev)->memmgr, 0, 0);
if (!job) {
err = -ENOMEM;
goto done;
@@ -396,38 +399,41 @@ int host1x_channel_read_3d_reg(
/* Switch to 3D - wait for it to complete what it was doing */
nvhost_cdma_push(&channel->cdma,
nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0),
- nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_OP_DONE,
+ nvhost_opcode_imm_incr_syncpt(
+ host1x_uclass_incr_syncpt_cond_op_done_v(),
p->syncpt));
nvhost_cdma_push(&channel->cdma,
nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
- NV_CLASS_HOST_WAIT_SYNCPT_BASE, 1),
+ host1x_uclass_wait_syncpt_base_r(), 1),
nvhost_class_host_wait_syncpt_base(p->syncpt,
p->waitbase, 1));
/* Tell 3D to send register value to FIFO */
nvhost_cdma_push(&channel->cdma,
- nvhost_opcode_nonincr(NV_CLASS_HOST_INDOFF, 1),
+ nvhost_opcode_nonincr(host1x_uclass_indoff_r(), 1),
nvhost_class_host_indoff_reg_read(NV_HOST_MODULE_GR3D,
offset, false));
nvhost_cdma_push(&channel->cdma,
- nvhost_opcode_imm(NV_CLASS_HOST_INDDATA, 0),
+ nvhost_opcode_imm(host1x_uclass_inddata_r(), 0),
NVHOST_OPCODE_NOOP);
/* Increment syncpt to indicate that FIFO can be read */
nvhost_cdma_push(&channel->cdma,
- nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_IMMEDIATE,
+ nvhost_opcode_imm_incr_syncpt(
+ host1x_uclass_incr_syncpt_cond_immediate_v(),
p->syncpt),
NVHOST_OPCODE_NOOP);
/* Wait for value to be read from FIFO */
nvhost_cdma_push(&channel->cdma,
- nvhost_opcode_nonincr(NV_CLASS_HOST_WAIT_SYNCPT_BASE, 1),
+ nvhost_opcode_nonincr(host1x_uclass_wait_syncpt_base_r(), 1),
nvhost_class_host_wait_syncpt_base(p->syncpt,
p->waitbase, 3));
/* Indicate submit complete */
nvhost_cdma_push(&channel->cdma,
- nvhost_opcode_nonincr(NV_CLASS_HOST_INCR_SYNCPT_BASE, 1),
+ nvhost_opcode_nonincr(host1x_uclass_incr_syncpt_base_r(), 1),
nvhost_class_host_incr_syncpt_base(p->waitbase, 4));
nvhost_cdma_push(&channel->cdma,
NVHOST_OPCODE_NOOP,
- nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_IMMEDIATE,
+ nvhost_opcode_imm_incr_syncpt(
+ host1x_uclass_incr_syncpt_cond_immediate_v(),
p->syncpt));
/* end CDMA submit */
@@ -467,8 +473,7 @@ int host1x_channel_read_3d_reg(
nvhost_intr_put_ref(&nvhost_get_host(channel->dev)->intr, ref);
/* Read the register value from FIFO */
- err = host1x_drain_read_fifo(channel->aperture,
- value, 1, &pending);
+ err = host1x_drain_read_fifo(channel, value, 1, &pending);
/* Indicate we've read the value */
nvhost_syncpt_cpu_incr(&nvhost_get_host(channel->dev)->syncpt,
@@ -492,18 +497,19 @@ done:
}
-int host1x_drain_read_fifo(void __iomem *chan_regs,
+static int host1x_drain_read_fifo(struct nvhost_channel *ch,
u32 *ptr, unsigned int count, unsigned int *pending)
{
unsigned int entries = *pending;
unsigned long timeout = jiffies + NV_FIFO_READ_TIMEOUT;
+ void __iomem *chan_regs = ch->aperture;
while (count) {
unsigned int num;
while (!entries && time_before(jiffies, timeout)) {
/* query host for number of entries in fifo */
- entries = HOST1X_VAL(CHANNEL_FIFOSTAT, OUTFENTRIES,
- readl(chan_regs + HOST1X_CHANNEL_FIFOSTAT));
+ entries = host1x_channel_fifostat_outfentries_v(
+ readl(chan_regs + host1x_channel_fifostat_r()));
if (!entries)
cpu_relax();
}
@@ -518,25 +524,25 @@ int host1x_drain_read_fifo(void __iomem *chan_regs,
while (num & ~0x3) {
u32 arr[4];
- arr[0] = readl(chan_regs + HOST1X_CHANNEL_INDDATA);
- arr[1] = readl(chan_regs + HOST1X_CHANNEL_INDDATA);
- arr[2] = readl(chan_regs + HOST1X_CHANNEL_INDDATA);
- arr[3] = readl(chan_regs + HOST1X_CHANNEL_INDDATA);
+ arr[0] = readl(chan_regs + host1x_channel_inddata_r());
+ arr[1] = readl(chan_regs + host1x_channel_inddata_r());
+ arr[2] = readl(chan_regs + host1x_channel_inddata_r());
+ arr[3] = readl(chan_regs + host1x_channel_inddata_r());
memcpy(ptr, arr, 4*sizeof(u32));
ptr += 4;
num -= 4;
}
while (num--)
- *ptr++ = readl(chan_regs + HOST1X_CHANNEL_INDDATA);
+ *ptr++ = readl(chan_regs + host1x_channel_inddata_r());
}
*pending = entries;
return 0;
}
-int host1x_save_context(struct nvhost_device *dev, u32 syncpt_id)
+static int host1x_save_context(struct nvhost_channel *ch)
{
- struct nvhost_channel *ch = dev->channel;
+ struct nvhost_device *dev = ch->dev;
struct nvhost_hwctx *hwctx_to_save;
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
u32 syncpt_incrs, syncpt_val;
@@ -544,6 +550,8 @@ int host1x_save_context(struct nvhost_device *dev, u32 syncpt_id)
void *ref;
void *ctx_waiter = NULL, *wakeup_waiter = NULL;
struct nvhost_job *job;
+ struct nvhost_driver *drv = to_nvhost_driver(dev->dev.driver);
+ u32 syncpt_id;
ctx_waiter = nvhost_intr_alloc_waiter();
wakeup_waiter = nvhost_intr_alloc_waiter();
@@ -552,8 +560,8 @@ int host1x_save_context(struct nvhost_device *dev, u32 syncpt_id)
goto done;
}
- if (dev->busy)
- dev->busy(dev);
+ if (drv->busy)
+ drv->busy(dev);
mutex_lock(&ch->submitlock);
hwctx_to_save = ch->cur_ctx;
@@ -564,7 +572,7 @@ int host1x_save_context(struct nvhost_device *dev, u32 syncpt_id)
job = nvhost_job_alloc(ch, hwctx_to_save,
NULL,
- nvhost_get_host(ch->dev)->nvmap, 0, 0);
+ nvhost_get_host(ch->dev)->memmgr, 0, 0);
if (IS_ERR_OR_NULL(job)) {
err = PTR_ERR(job);
mutex_unlock(&ch->submitlock);
@@ -574,6 +582,7 @@ int host1x_save_context(struct nvhost_device *dev, u32 syncpt_id)
hwctx_to_save->valid = true;
ch->ctxhandler->get(hwctx_to_save);
ch->cur_ctx = NULL;
+ syncpt_id = to_host1x_hwctx_handler(hwctx_to_save->h)->syncpt;
syncpt_incrs = to_host1x_hwctx(hwctx_to_save)->save_incrs;
syncpt_val = nvhost_syncpt_incr_max(&nvhost_get_host(ch->dev)->syncpt,
@@ -625,3 +634,48 @@ done:
kfree(wakeup_waiter);
return err;
}
+
+static inline void __iomem *host1x_channel_aperture(void __iomem *p, int ndx)
+{
+ p += ndx * NV_HOST1X_CHANNEL_MAP_SIZE_BYTES;
+ return p;
+}
+
+static inline int host1x_hwctx_handler_init(struct nvhost_channel *ch)
+{
+ int err = 0;
+ unsigned long syncpts = ch->dev->syncpts;
+ unsigned long waitbases = ch->dev->waitbases;
+ u32 syncpt = find_first_bit(&syncpts, BITS_PER_LONG);
+ u32 waitbase = find_first_bit(&waitbases, BITS_PER_LONG);
+ struct nvhost_driver *drv = to_nvhost_driver(ch->dev->dev.driver);
+
+ if (drv->alloc_hwctx_handler) {
+ ch->ctxhandler = drv->alloc_hwctx_handler(syncpt,
+ waitbase, ch);
+ if (!ch->ctxhandler)
+ err = -ENOMEM;
+ }
+
+ return err;
+}
+
+static int host1x_channel_init(struct nvhost_channel *ch,
+ struct nvhost_master *dev, int index)
+{
+ ch->chid = index;
+ mutex_init(&ch->reflock);
+ mutex_init(&ch->submitlock);
+
+ ch->aperture = host1x_channel_aperture(dev->aperture, index);
+
+ return host1x_hwctx_handler_init(ch);
+}
+
+static const struct nvhost_channel_ops host1x_channel_ops = {
+ .init = host1x_channel_init,
+ .submit = host1x_channel_submit,
+ .read3dreg = host1x_channel_read_3d_reg,
+ .save_context = host1x_save_context,
+ .drain_read_fifo = host1x_drain_read_fifo,
+};
diff --git a/drivers/video/tegra/host/host1x/host1x_channel.h b/drivers/video/tegra/host/host1x/host1x_channel.h
deleted file mode 100644
index 4113dbcada20..000000000000
--- a/drivers/video/tegra/host/host1x/host1x_channel.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * drivers/video/tegra/host/host1x/host1x_channel.h
- *
- * Tegra Graphics Host Channel
- *
- * Copyright (c) 2011-2012, NVIDIA Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __NVHOST_HOST1X_CHANNEL_H
-#define __NVHOST_HOST1X_CHANNEL_H
-
-struct nvhost_job;
-struct nvhost_channel;
-struct nvhost_hwctx;
-struct nvhost_device;
-
-/* Submit job to a host1x client */
-int host1x_channel_submit(struct nvhost_job *job);
-
-/* Read 3d register via FIFO */
-int host1x_channel_read_3d_reg(
- struct nvhost_channel *channel,
- struct nvhost_hwctx *hwctx,
- u32 offset,
- u32 *value);
-
-/* Reads words from FIFO */
-int host1x_drain_read_fifo(void __iomem *chan_regs,
- u32 *ptr, unsigned int count, unsigned int *pending);
-
-int host1x_save_context(struct nvhost_device *dev, u32 syncpt_id);
-
-#endif
diff --git a/drivers/video/tegra/host/host1x/host1x_debug.c b/drivers/video/tegra/host/host1x/host1x_debug.c
index 1a1d764bbd63..1c4ed684dd84 100644
--- a/drivers/video/tegra/host/host1x/host1x_debug.c
+++ b/drivers/video/tegra/host/host1x/host1x_debug.c
@@ -26,10 +26,10 @@
#include "dev.h"
#include "debug.h"
#include "nvhost_cdma.h"
-#include "../../nvmap/nvmap.h"
-
-#include "host1x_hardware.h"
-#include "host1x_cdma.h"
+#include "nvhost_channel.h"
+#include "nvhost_job.h"
+#include "chip_support.h"
+#include "nvhost_memmgr.h"
#define NVHOST_DEBUG_MAX_PAGE_OFFSET 102400
@@ -160,49 +160,15 @@ static void show_channel_word(struct output *o, int *state, int *count,
}
}
-static void show_channel_gather(struct output *o, u32 addr,
+static void do_show_channel_gather(struct output *o,
phys_addr_t phys_addr,
- u32 words, struct nvhost_cdma *cdma)
+ u32 words, struct nvhost_cdma *cdma,
+ phys_addr_t pin_addr, u32 *map_addr)
{
-#if defined(CONFIG_TEGRA_NVMAP)
/* Map dmaget cursor to corresponding nvmap_handle */
- struct push_buffer *pb = &cdma->push_buffer;
- u32 cur = addr - pb->phys;
- struct nvmap_client_handle *nvmap = &pb->nvmap[cur/8];
- struct nvmap_handle_ref ref;
- u32 *map_addr, offset;
- phys_addr_t pin_addr;
+ u32 offset;
int state, count, i;
- if ((u32)nvmap->handle == NVHOST_CDMA_PUSH_GATHER_CTXSAVE) {
- nvhost_debug_output(o, "[context save]\n");
- return;
- }
-
- if (!nvmap->handle || !nvmap->client
- || atomic_read(&nvmap->handle->ref) < 1) {
- nvhost_debug_output(o, "[already deallocated]\n");
- return;
- }
-
- /* Create a fake nvmap_handle_ref - nvmap requires it
- * but accesses only the first field - nvmap_handle */
- ref.handle = nvmap->handle;
-
- map_addr = nvmap_mmap(&ref);
- if (!map_addr) {
- nvhost_debug_output(o, "[could not mmap]\n");
- return;
- }
-
- /* Get base address from nvmap */
- pin_addr = nvmap_pin(nvmap->client, &ref);
- if (IS_ERR_VALUE(pin_addr)) {
- nvhost_debug_output(o, "[couldn't pin]\n");
- nvmap_munmap(&ref, map_addr);
- return;
- }
-
offset = phys_addr - pin_addr;
/*
* Sometimes we're given different hardware address to the same
@@ -220,42 +186,81 @@ static void show_channel_gather(struct output *o, u32 addr,
*(map_addr + offset/4 + i),
cdma);
}
- nvmap_unpin(nvmap->client, &ref);
- nvmap_munmap(&ref, map_addr);
-#endif
}
-static void show_channel_pair(struct output *o, u32 addr,
- u32 w0, u32 w1, struct nvhost_cdma *cdma)
+static void show_channel_gather(struct output *o, u32 addr,
+ phys_addr_t phys_addr,
+ u32 words, struct nvhost_cdma *cdma)
{
- int state = NVHOST_DBG_STATE_CMD;
- int count;
+#if defined(CONFIG_TEGRA_NVMAP)
+ /* Map dmaget cursor to corresponding nvmap_handle */
+ struct push_buffer *pb = &cdma->push_buffer;
+ u32 cur = addr - pb->phys;
+ struct mem_mgr_handle *nvmap = &pb->client_handle[cur/8];
+ u32 *map_addr, offset;
+ phys_addr_t pin_addr;
- show_channel_word(o, &state, &count, addr, w0, cdma);
- show_channel_word(o, &state, &count, addr+4, w1, cdma);
-}
+ if (!nvmap || !nvmap->handle || !nvmap->client) {
+ nvhost_debug_output(o, "[already deallocated]\n");
+ return;
+ }
-/**
- * Retrieve the op pair at a slot offset from a DMA address
- */
-static void cdma_peek(struct nvhost_cdma *cdma,
- u32 dmaget, int slot, u32 *out)
-{
- u32 offset = dmaget - cdma->push_buffer.phys;
- u32 *p = cdma->push_buffer.mapped;
+ map_addr = mem_op().mmap(nvmap->handle);
+ if (!map_addr) {
+ nvhost_debug_output(o, "[could not mmap]\n");
+ return;
+ }
+
+ /* Get base address from nvmap */
+ pin_addr = mem_op().pin(nvmap->client, nvmap->handle);
+ if (IS_ERR_VALUE(pin_addr)) {
+ nvhost_debug_output(o, "[couldn't pin]\n");
+ mem_op().munmap(nvmap->handle, map_addr);
+ return;
+ }
- offset = ((offset + slot * 8) & (PUSH_BUFFER_SIZE - 1)) >> 2;
- out[0] = p[offset];
- out[1] = p[offset + 1];
+ offset = phys_addr - pin_addr;
+ do_show_channel_gather(o, phys_addr, words, cdma,
+ pin_addr, map_addr);
+ mem_op().unpin(nvmap->client, nvmap->handle);
+ mem_op().munmap(nvmap->handle, map_addr);
+#endif
}
-u32 previous_oppair(struct nvhost_cdma *cdma, u32 cur)
+static void show_channel_gathers(struct output *o, struct nvhost_cdma *cdma)
{
- u32 pb = cdma->push_buffer.phys;
- u32 prev = cur-8;
- if (prev < pb)
- prev += PUSH_BUFFER_SIZE;
- return prev;
+ struct nvhost_job *job;
+
+ list_for_each_entry(job, &cdma->sync_queue, list) {
+ int i;
+ nvhost_debug_output(o, "\n%p: JOB, syncpt_id=%d, syncpt_val=%d,"
+ " first_get=%08x, timeout=%d, ctx=%p,"
+ " num_slots=%d, num_handles=%d\n",
+ job,
+ job->syncpt_id,
+ job->syncpt_end,
+ job->first_get,
+ job->timeout,
+ job->hwctx,
+ job->num_slots,
+ job->num_unpins);
+
+ for (i = 0; i < job->num_gathers; i++) {
+ struct nvhost_job_gather *g = &job->gathers[i];
+ u32 *mapped = mem_op().mmap(g->ref);
+ if (!mapped) {
+ nvhost_debug_output(o, "[could not mmap]\n");
+ continue;
+ }
+
+ nvhost_debug_output(o, " GATHER at %08x, %d words\n",
+ g->mem, g->words);
+
+ do_show_channel_gather(o, g->mem + g->offset,
+ g->words, cdma, g->mem, mapped);
+ mem_op().munmap(g->ref, mapped);
+ }
+ }
}
static void t20_debug_show_channel_cdma(struct nvhost_master *m,
@@ -266,19 +271,18 @@ static void t20_debug_show_channel_cdma(struct nvhost_master *m,
u32 dmaput, dmaget, dmactrl;
u32 cbstat, cbread;
u32 val, base, baseval;
- u32 pbw[2];
- dmaput = readl(channel->aperture + HOST1X_CHANNEL_DMAPUT);
- dmaget = readl(channel->aperture + HOST1X_CHANNEL_DMAGET);
- dmactrl = readl(channel->aperture + HOST1X_CHANNEL_DMACTRL);
- cbread = readl(m->sync_aperture + HOST1X_SYNC_CBREAD_x(chid));
- cbstat = readl(m->sync_aperture + HOST1X_SYNC_CBSTAT_x(chid));
+ dmaput = readl(channel->aperture + host1x_channel_dmaput_r());
+ dmaget = readl(channel->aperture + host1x_channel_dmaget_r());
+ dmactrl = readl(channel->aperture + host1x_channel_dmactrl_r());
+ cbread = readl(m->sync_aperture + host1x_sync_cbread0_r() + 4 * chid);
+ cbstat = readl(m->sync_aperture + host1x_sync_cbstat_0_r() + 4 * chid);
nvhost_debug_output(o, "%d-%s (%d): ", chid,
channel->dev->name,
channel->dev->refcount);
- if (HOST1X_VAL(CHANNEL_DMACTRL, DMASTOP, dmactrl)
+ if (host1x_channel_dmactrl_dmastop_v(dmactrl)
|| !channel->cdma.push_buffer.mapped) {
nvhost_debug_output(o, "inactive\n\n");
return;
@@ -292,9 +296,8 @@ static void t20_debug_show_channel_cdma(struct nvhost_master *m,
case 0x00010009:
base = (cbread >> 16) & 0xff;
- val = readl(m->sync_aperture +
- HOST1X_SYNC_SYNCPT_BASE_x(base));
- baseval = HOST1X_VAL(SYNC_SYNCPT_BASE_0, BASE, val);
+ baseval = readl(m->sync_aperture +
+ host1x_sync_syncpt_base_0_r() + 4 * base);
val = cbread & 0xffff;
nvhost_debug_output(o, "waiting on syncpt %d val %d "
"(base %d = %d; offset = %d)\n",
@@ -305,8 +308,8 @@ static void t20_debug_show_channel_cdma(struct nvhost_master *m,
default:
nvhost_debug_output(o,
"active class %02x, offset %04x, val %08x\n",
- HOST1X_VAL(SYNC_CBSTAT_0, CBCLASS0, cbstat),
- HOST1X_VAL(SYNC_CBSTAT_0, CBOFFSET0, cbstat),
+ host1x_sync_cbstat_0_cbclass0_v(cbstat),
+ host1x_sync_cbstat_0_cboffset0_v(cbstat),
cbread);
break;
}
@@ -315,13 +318,11 @@ static void t20_debug_show_channel_cdma(struct nvhost_master *m,
dmaput, dmaget, dmactrl);
nvhost_debug_output(o, "CBREAD %08x, CBSTAT %08x\n", cbread, cbstat);
- cdma_peek(cdma, dmaget, -1, pbw);
- show_channel_pair(o, previous_oppair(cdma, dmaget),
- pbw[0], pbw[1], &channel->cdma);
+ show_channel_gathers(o, cdma);
nvhost_debug_output(o, "\n");
}
-void t20_debug_show_channel_fifo(struct nvhost_master *m,
+static void t20_debug_show_channel_fifo(struct nvhost_master *m,
struct nvhost_channel *ch, struct output *o, int chid)
{
u32 val, rd_ptr, wr_ptr, start, end;
@@ -330,35 +331,35 @@ void t20_debug_show_channel_fifo(struct nvhost_master *m,
nvhost_debug_output(o, "%d: fifo:\n", chid);
- val = readl(channel->aperture + HOST1X_CHANNEL_FIFOSTAT);
+ val = readl(channel->aperture + host1x_channel_fifostat_r());
nvhost_debug_output(o, "FIFOSTAT %08x\n", val);
- if (HOST1X_VAL(CHANNEL_FIFOSTAT, CFEMPTY, val)) {
+ if (host1x_channel_fifostat_cfempty_v(val)) {
nvhost_debug_output(o, "[empty]\n");
return;
}
- writel(0x0, m->sync_aperture + HOST1X_SYNC_CFPEEK_CTRL);
- writel(HOST1X_CREATE(SYNC_CFPEEK_CTRL, ENA, 1)
- | HOST1X_CREATE(SYNC_CFPEEK_CTRL, CHANNR, chid),
- m->sync_aperture + HOST1X_SYNC_CFPEEK_CTRL);
+ writel(0x0, m->sync_aperture + host1x_sync_cfpeek_ctrl_r());
+ writel(host1x_sync_cfpeek_ctrl_cfpeek_ena_f(1)
+ | host1x_sync_cfpeek_ctrl_cfpeek_channr_f(chid),
+ m->sync_aperture + host1x_sync_cfpeek_ctrl_r());
- val = readl(m->sync_aperture + HOST1X_SYNC_CFPEEK_PTRS);
- rd_ptr = HOST1X_VAL(SYNC_CFPEEK_PTRS, CF_RD_PTR, val);
- wr_ptr = HOST1X_VAL(SYNC_CFPEEK_PTRS, CF_WR_PTR, val);
+ val = readl(m->sync_aperture + host1x_sync_cfpeek_ptrs_r());
+ rd_ptr = host1x_sync_cfpeek_ptrs_cf_rd_ptr_v(val);
+ wr_ptr = host1x_sync_cfpeek_ptrs_cf_wr_ptr_v(val);
- val = readl(m->sync_aperture + HOST1X_SYNC_CFx_SETUP(chid));
- start = HOST1X_VAL(SYNC_CF0_SETUP, BASE, val);
- end = HOST1X_VAL(SYNC_CF0_SETUP, LIMIT, val);
+ val = readl(m->sync_aperture + host1x_sync_cf0_setup_r() + 4 * chid);
+ start = host1x_sync_cf0_setup_cf0_base_v(val);
+ end = host1x_sync_cf0_setup_cf0_limit_v(val);
state = NVHOST_DBG_STATE_CMD;
do {
- writel(0x0, m->sync_aperture + HOST1X_SYNC_CFPEEK_CTRL);
- writel(HOST1X_CREATE(SYNC_CFPEEK_CTRL, ENA, 1)
- | HOST1X_CREATE(SYNC_CFPEEK_CTRL, CHANNR, chid)
- | HOST1X_CREATE(SYNC_CFPEEK_CTRL, ADDR, rd_ptr),
- m->sync_aperture + HOST1X_SYNC_CFPEEK_CTRL);
- val = readl(m->sync_aperture + HOST1X_SYNC_CFPEEK_READ);
+ writel(0x0, m->sync_aperture + host1x_sync_cfpeek_ctrl_r());
+ writel(host1x_sync_cfpeek_ctrl_cfpeek_ena_f(1)
+ | host1x_sync_cfpeek_ctrl_cfpeek_channr_f(chid)
+ | host1x_sync_cfpeek_ctrl_cfpeek_addr_f(rd_ptr),
+ m->sync_aperture + host1x_sync_cfpeek_ctrl_r());
+ val = readl(m->sync_aperture + host1x_sync_cfpeek_read_r());
show_channel_word(o, &state, &count, 0, val, NULL);
@@ -372,21 +373,24 @@ void t20_debug_show_channel_fifo(struct nvhost_master *m,
nvhost_debug_output(o, ", ...])\n");
nvhost_debug_output(o, "\n");
- writel(0x0, m->sync_aperture + HOST1X_SYNC_CFPEEK_CTRL);
+ writel(0x0, m->sync_aperture + host1x_sync_cfpeek_ctrl_r());
}
static void t20_debug_show_mlocks(struct nvhost_master *m, struct output *o)
{
- u32 __iomem *mlo_regs = m->sync_aperture + HOST1X_SYNC_MLOCK_OWNER_0;
+ u32 __iomem *mlo_regs = m->sync_aperture +
+ host1x_sync_mlock_owner_0_r();
int i;
nvhost_debug_output(o, "---- mlocks ----\n");
for (i = 0; i < NV_HOST1X_NB_MLOCKS; i++) {
u32 owner = readl(mlo_regs + i);
- if (HOST1X_VAL(SYNC_MLOCK_OWNER_0, CH_OWNS, owner))
+ if (host1x_sync_mlock_owner_0_mlock_ch_owns_0_v(owner))
nvhost_debug_output(o, "%d: locked by channel %d\n",
- i, HOST1X_VAL(SYNC_MLOCK_OWNER_0, CHID, owner));
- else if (HOST1X_VAL(SYNC_MLOCK_OWNER_0, CPU_OWNS, owner))
+ i,
+ host1x_sync_mlock_owner_0_mlock_owner_chid_0_f(
+ owner));
+ else if (host1x_sync_mlock_owner_0_mlock_cpu_owns_0_v(owner))
nvhost_debug_output(o, "%d: locked by cpu\n", i);
else
nvhost_debug_output(o, "%d: unlocked\n", i);
@@ -394,11 +398,8 @@ static void t20_debug_show_mlocks(struct nvhost_master *m, struct output *o)
nvhost_debug_output(o, "\n");
}
-int nvhost_init_t20_debug_support(struct nvhost_master *host)
-{
- host->op.debug.show_channel_cdma = t20_debug_show_channel_cdma;
- host->op.debug.show_channel_fifo = t20_debug_show_channel_fifo;
- host->op.debug.show_mlocks = t20_debug_show_mlocks;
-
- return 0;
-}
+static const struct nvhost_debug_ops host1x_debug_ops = {
+ .show_channel_cdma = t20_debug_show_channel_cdma,
+ .show_channel_fifo = t20_debug_show_channel_fifo,
+ .show_mlocks = t20_debug_show_mlocks,
+};
diff --git a/drivers/video/tegra/host/host1x/host1x_hardware.h b/drivers/video/tegra/host/host1x/host1x_hardware.h
deleted file mode 100644
index d13d57523644..000000000000
--- a/drivers/video/tegra/host/host1x/host1x_hardware.h
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * drivers/video/tegra/host/host1x/host1x_hardware.h
- *
- * Tegra Graphics Host Register Offsets
- *
- * Copyright (c) 2010-2012 NVIDIA Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __NVHOST_HOST1X_HOST1X_HARDWARE_H
-#define __NVHOST_HOST1X_HOST1X_HARDWARE_H
-
-#include <linux/types.h>
-#include <linux/bitops.h>
-
-/* class ids */
-enum {
- NV_HOST1X_CLASS_ID = 0x1,
- NV_VIDEO_ENCODE_MPEG_CLASS_ID = 0x20,
- NV_GRAPHICS_3D_CLASS_ID = 0x60
-};
-
-
-/* channel registers */
-#define NV_HOST1X_CHANNELS 8
-#define NV_HOST1X_CHANNEL0_BASE 0
-#define NV_HOST1X_CHANNEL_MAP_SIZE_BYTES 16384
-#define NV_HOST1X_SYNC_MLOCK_NUM 16
-
-#define HOST1X_VAL(reg, field, regdata) \
- ((regdata >> HOST1X_##reg##_##field##_SHIFT) \
- & HOST1X_##reg##_##field##_MASK)
-#define HOST1X_CREATE(reg, field, data) \
- ((data & HOST1X_##reg##_##field##_MASK) \
- << HOST1X_##reg##_##field##_SHIFT) \
-
-#define HOST1X_CHANNEL_FIFOSTAT 0x00
-#define HOST1X_CHANNEL_FIFOSTAT_CFEMPTY_SHIFT 10
-#define HOST1X_CHANNEL_FIFOSTAT_CFEMPTY_MASK 0x1
-#define HOST1X_CHANNEL_FIFOSTAT_OUTFENTRIES_SHIFT 24
-#define HOST1X_CHANNEL_FIFOSTAT_OUTFENTRIES_MASK 0x1f
-#define HOST1X_CHANNEL_INDDATA 0x0c
-#define HOST1X_CHANNEL_DMASTART 0x14
-#define HOST1X_CHANNEL_DMAPUT 0x18
-#define HOST1X_CHANNEL_DMAGET 0x1c
-#define HOST1X_CHANNEL_DMAEND 0x20
-#define HOST1X_CHANNEL_DMACTRL 0x24
-#define HOST1X_CHANNEL_DMACTRL_DMASTOP_SHIFT 0
-#define HOST1X_CHANNEL_DMACTRL_DMASTOP_MASK 0x1
-#define HOST1X_CHANNEL_DMACTRL_DMAGETRST_SHIFT 1
-#define HOST1X_CHANNEL_DMACTRL_DMAGETRST_MASK 0x1
-#define HOST1X_CHANNEL_DMACTRL_DMAINITGET_SHIFT 2
-#define HOST1X_CHANNEL_DMACTRL_DMAINITGET_MASK 0x1
-
-#define HOST1X_CHANNEL_SYNC_REG_BASE 0x3000
-
-#define HOST1X_SYNC_INTMASK 0x4
-#define HOST1X_SYNC_INTC0MASK 0x8
-#define HOST1X_SYNC_HINTSTATUS 0x20
-#define HOST1X_SYNC_HINTMASK 0x24
-#define HOST1X_SYNC_HINTSTATUS_EXT 0x28
-#define HOST1X_SYNC_HINTSTATUS_EXT_IP_READ_INT_SHIFT 30
-#define HOST1X_SYNC_HINTSTATUS_EXT_IP_READ_INT_MASK 0x1
-#define HOST1X_SYNC_HINTSTATUS_EXT_IP_WRITE_INT_SHIFT 31
-#define HOST1X_SYNC_HINTSTATUS_EXT_IP_WRITE_INT_MASK 0x1
-#define HOST1X_SYNC_HINTMASK_EXT 0x2c
-#define HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS 0x40
-#define HOST1X_SYNC_SYNCPT_THRESH_CPU1_INT_STATUS 0x48
-#define HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE 0x60
-#define HOST1X_SYNC_SYNCPT_THRESH_INT_ENABLE_CPU0 0x68
-#define HOST1X_SYNC_CF0_SETUP 0x80
-#define HOST1X_SYNC_CF0_SETUP_BASE_SHIFT 0
-#define HOST1X_SYNC_CF0_SETUP_BASE_MASK 0x1ff
-#define HOST1X_SYNC_CF0_SETUP_LIMIT_SHIFT 16
-#define HOST1X_SYNC_CF0_SETUP_LIMIT_MASK 0x1ff
-#define HOST1X_SYNC_CFx_SETUP(x) (HOST1X_SYNC_CF0_SETUP + (4 * (x)))
-
-#define HOST1X_SYNC_CMDPROC_STOP 0xac
-#define HOST1X_SYNC_CH_TEARDOWN 0xb0
-#define HOST1X_SYNC_USEC_CLK 0x1a4
-#define HOST1X_SYNC_CTXSW_TIMEOUT_CFG 0x1a8
-#define HOST1X_SYNC_IP_BUSY_TIMEOUT 0x1bc
-#define HOST1X_SYNC_IP_READ_TIMEOUT_ADDR 0x1c0
-#define HOST1X_SYNC_IP_WRITE_TIMEOUT_ADDR 0x1c4
-#define HOST1X_SYNC_MLOCK_0 0x2c0
-#define HOST1X_SYNC_MLOCK_OWNER_0 0x340
-#define HOST1X_SYNC_MLOCK_OWNER_0_CHID_SHIFT 8
-#define HOST1X_SYNC_MLOCK_OWNER_0_CHID_MASK 0xf
-#define HOST1X_SYNC_MLOCK_OWNER_0_CPU_OWNS_SHIFT 1
-#define HOST1X_SYNC_MLOCK_OWNER_0_CPU_OWNS_MASK 0x1
-#define HOST1X_SYNC_MLOCK_OWNER_0_CH_OWNS_SHIFT 0
-#define HOST1X_SYNC_MLOCK_OWNER_0_CH_OWNS_MASK 0x1
-#define HOST1X_SYNC_SYNCPT_0 0x400
-#define HOST1X_SYNC_SYNCPT_INT_THRESH_0 0x500
-
-#define HOST1X_SYNC_SYNCPT_BASE_0 0x600
-#define HOST1X_SYNC_SYNCPT_BASE_0_BASE_SHIFT 0
-#define HOST1X_SYNC_SYNCPT_BASE_0_BASE_MASK 0xffff
-#define HOST1X_SYNC_SYNCPT_BASE_x(x) (HOST1X_SYNC_SYNCPT_BASE_0 + (4 * (x)))
-
-#define HOST1X_SYNC_SYNCPT_CPU_INCR 0x700
-
-#define HOST1X_SYNC_CBREAD_0 0x720
-#define HOST1X_SYNC_CBREAD_x(x) (HOST1X_SYNC_CBREAD_0 + (4 * (x)))
-#define HOST1X_SYNC_CFPEEK_CTRL 0x74c
-#define HOST1X_SYNC_CFPEEK_CTRL_ADDR_SHIFT 0
-#define HOST1X_SYNC_CFPEEK_CTRL_ADDR_MASK 0x1ff
-#define HOST1X_SYNC_CFPEEK_CTRL_CHANNR_SHIFT 16
-#define HOST1X_SYNC_CFPEEK_CTRL_CHANNR_MASK 0x7
-#define HOST1X_SYNC_CFPEEK_CTRL_ENA_SHIFT 31
-#define HOST1X_SYNC_CFPEEK_CTRL_ENA_MASK 0x1
-#define HOST1X_SYNC_CFPEEK_READ 0x750
-#define HOST1X_SYNC_CFPEEK_PTRS 0x754
-#define HOST1X_SYNC_CFPEEK_PTRS_CF_RD_PTR_SHIFT 0
-#define HOST1X_SYNC_CFPEEK_PTRS_CF_RD_PTR_MASK 0x1ff
-#define HOST1X_SYNC_CFPEEK_PTRS_CF_WR_PTR_SHIFT 16
-#define HOST1X_SYNC_CFPEEK_PTRS_CF_WR_PTR_MASK 0x1ff
-#define HOST1X_SYNC_CBSTAT_0 0x758
-#define HOST1X_SYNC_CBSTAT_0_CBOFFSET0_SHIFT 0
-#define HOST1X_SYNC_CBSTAT_0_CBOFFSET0_MASK 0xffff
-#define HOST1X_SYNC_CBSTAT_0_CBCLASS0_SHIFT 16
-#define HOST1X_SYNC_CBSTAT_0_CBCLASS0_MASK 0xffff
-#define HOST1X_SYNC_CBSTAT_x(x) (HOST1X_SYNC_CBSTAT_0 + (4 * (x)))
-
-/* sync registers */
-#define NV_HOST1X_SYNCPT_NB_PTS 32
-#define NV_HOST1X_SYNCPT_NB_BASES 8
-#define NV_HOST1X_NB_MLOCKS 16
-
-/* host class methods */
-enum {
- NV_CLASS_HOST_INCR_SYNCPT = 0x0,
- NV_CLASS_HOST_WAIT_SYNCPT = 0x8,
- NV_CLASS_HOST_WAIT_SYNCPT_BASE = 0x9,
- NV_CLASS_HOST_LOAD_SYNCPT_BASE = 0xb,
- NV_CLASS_HOST_INCR_SYNCPT_BASE = 0xc,
- NV_CLASS_HOST_INDOFF = 0x2d,
- NV_CLASS_HOST_INDDATA = 0x2e
-};
-/* sync point conditionals */
-enum {
- NV_SYNCPT_IMMEDIATE = 0x0,
- NV_SYNCPT_OP_DONE = 0x1,
- NV_SYNCPT_RD_DONE = 0x2,
- NV_SYNCPT_REG_WR_SAFE = 0x3,
-};
-
-static inline u32 nvhost_class_host_wait_syncpt(
- unsigned indx, unsigned threshold)
-{
- return (indx << 24) | (threshold & 0xffffff);
-}
-
-static inline u32 nvhost_class_host_load_syncpt_base(
- unsigned indx, unsigned threshold)
-{
- return (indx << 24) | (threshold & 0xffffff);
-}
-
-static inline u32 nvhost_class_host_wait_syncpt_base(
- unsigned indx, unsigned base_indx, unsigned offset)
-{
- return (indx << 24) | (base_indx << 16) | offset;
-}
-
-static inline u32 nvhost_class_host_incr_syncpt_base(
- unsigned base_indx, unsigned offset)
-{
- return (base_indx << 24) | offset;
-}
-
-static inline u32 nvhost_class_host_incr_syncpt(
- unsigned cond, unsigned indx)
-{
- return (cond << 8) | indx;
-}
-
-enum {
- NV_HOST_MODULE_HOST1X = 0,
- NV_HOST_MODULE_MPE = 1,
- NV_HOST_MODULE_GR3D = 6
-};
-
-static inline u32 nvhost_class_host_indoff_reg_write(
- unsigned mod_id, unsigned offset, bool auto_inc)
-{
- u32 v = (0xf << 28) | (mod_id << 18) | (offset << 2);
- if (auto_inc)
- v |= BIT(27);
- return v;
-}
-
-static inline u32 nvhost_class_host_indoff_reg_read(
- unsigned mod_id, unsigned offset, bool auto_inc)
-{
- u32 v = (mod_id << 18) | (offset << 2) | 1;
- if (auto_inc)
- v |= BIT(27);
- return v;
-}
-
-
-/* cdma opcodes */
-static inline u32 nvhost_opcode_setclass(
- unsigned class_id, unsigned offset, unsigned mask)
-{
- return (0 << 28) | (offset << 16) | (class_id << 6) | mask;
-}
-
-static inline u32 nvhost_opcode_incr(unsigned offset, unsigned count)
-{
- return (1 << 28) | (offset << 16) | count;
-}
-
-static inline u32 nvhost_opcode_nonincr(unsigned offset, unsigned count)
-{
- return (2 << 28) | (offset << 16) | count;
-}
-
-static inline u32 nvhost_opcode_mask(unsigned offset, unsigned mask)
-{
- return (3 << 28) | (offset << 16) | mask;
-}
-
-static inline u32 nvhost_opcode_imm(unsigned offset, unsigned value)
-{
- return (4 << 28) | (offset << 16) | value;
-}
-
-static inline u32 nvhost_opcode_imm_incr_syncpt(unsigned cond, unsigned indx)
-{
- return nvhost_opcode_imm(NV_CLASS_HOST_INCR_SYNCPT,
- nvhost_class_host_incr_syncpt(cond, indx));
-}
-
-static inline u32 nvhost_opcode_restart(unsigned address)
-{
- return (5 << 28) | (address >> 4);
-}
-
-static inline u32 nvhost_opcode_gather(unsigned count)
-{
- return (6 << 28) | count;
-}
-
-static inline u32 nvhost_opcode_gather_nonincr(unsigned offset, unsigned count)
-{
- return (6 << 28) | (offset << 16) | BIT(15) | count;
-}
-
-static inline u32 nvhost_opcode_gather_incr(unsigned offset, unsigned count)
-{
- return (6 << 28) | (offset << 16) | BIT(15) | BIT(14) | count;
-}
-
-#define NVHOST_OPCODE_NOOP nvhost_opcode_nonincr(0, 0)
-
-static inline u32 nvhost_mask2(unsigned x, unsigned y)
-{
- return 1 | (1 << (y - x));
-}
-
-#endif
diff --git a/drivers/video/tegra/host/host1x/host1x_hwctx.h b/drivers/video/tegra/host/host1x/host1x_hwctx.h
index 7587642d0e14..13f0071d1e33 100644
--- a/drivers/video/tegra/host/host1x/host1x_hwctx.h
+++ b/drivers/video/tegra/host/host1x/host1x_hwctx.h
@@ -24,6 +24,7 @@
#define __NVHOST_HOST1X_HWCTX_H
#include <linux/kref.h>
+#include "nvhost_hwctx.h"
struct nvhost_hwctx_handler;
struct nvhost_channel;
@@ -40,7 +41,7 @@ struct host1x_hwctx {
u32 save_thresh;
u32 save_slots;
- struct nvmap_handle_ref *restore;
+ struct mem_handle *restore;
u32 *restore_virt;
phys_addr_t restore_phys;
u32 restore_size;
@@ -54,7 +55,7 @@ struct host1x_hwctx_handler {
u32 waitbase;
u32 restore_size;
u32 restore_incrs;
- struct nvmap_handle_ref *save_buf;
+ struct mem_handle *save_buf;
u32 save_incrs;
u32 save_thresh;
u32 save_slots;
diff --git a/drivers/video/tegra/host/host1x/host1x_intr.c b/drivers/video/tegra/host/host1x/host1x_intr.c
index 47e984e2943e..62fd07cbb9ba 100644
--- a/drivers/video/tegra/host/host1x/host1x_intr.c
+++ b/drivers/video/tegra/host/host1x/host1x_intr.c
@@ -3,6 +3,7 @@
*
* Tegra Graphics Host Interrupt Management
*
+ * Copyright (C) 2010 Google, Inc.
* Copyright (c) 2010-2012, NVIDIA Corporation.
*
* This program is free software; you can redistribute it and/or modify it
@@ -20,27 +21,86 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
+#include <linux/io.h>
+#include <asm/mach/irq.h>
#include "nvhost_intr.h"
#include "dev.h"
-#include "host1x_hardware.h"
+/* Spacing between sync registers */
+#define REGISTER_STRIDE 4
/*** HW host sync management ***/
+static void syncpt_thresh_mask(struct irq_data *data)
+{
+ (void)data;
+}
+
+static void syncpt_thresh_unmask(struct irq_data *data)
+{
+ (void)data;
+}
+
+static void syncpt_thresh_cascade(unsigned int irq, struct irq_desc *desc)
+{
+ struct nvhost_master *dev = irq_desc_get_handler_data(desc);
+ void __iomem *sync_regs = dev->sync_aperture;
+ unsigned long reg;
+ int i, id;
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+
+ chained_irq_enter(chip, desc);
+
+ for (i = 0; i < dev->info.nb_pts / BITS_PER_LONG; i++) {
+ reg = readl(sync_regs +
+ host1x_sync_syncpt_thresh_cpu0_int_status_r() +
+ i * REGISTER_STRIDE);
+ for_each_set_bit(id, &reg, BITS_PER_LONG)
+ generic_handle_irq(id +
+ dev->intr.host_syncpt_irq_base +
+ i * BITS_PER_LONG);
+ }
+
+ chained_irq_exit(chip, desc);
+}
+
+static struct irq_chip syncpt_thresh_irq = {
+ .name = "syncpt",
+ .irq_mask = syncpt_thresh_mask,
+ .irq_unmask = syncpt_thresh_unmask
+};
+
static void t20_intr_init_host_sync(struct nvhost_intr *intr)
{
struct nvhost_master *dev = intr_to_dev(intr);
void __iomem *sync_regs = dev->sync_aperture;
+ int i, irq;
+
+ writel(0xffffffffUL,
+ sync_regs + host1x_sync_syncpt_thresh_int_disable_r());
+ writel(0xffffffffUL,
+ sync_regs + host1x_sync_syncpt_thresh_cpu0_int_status_r());
+
+ for (i = 0; i < dev->info.nb_pts; i++) {
+ irq = intr->host_syncpt_irq_base + i;
+ irq_set_chip_and_handler(irq, &syncpt_thresh_irq,
+ handle_simple_irq);
+ irq_set_chip_data(irq, sync_regs);
+ set_irq_flags(irq, IRQF_VALID);
+ }
+ irq_set_chained_handler(INT_HOST1X_MPCORE_SYNCPT,
+ syncpt_thresh_cascade);
+ irq_set_handler_data(INT_HOST1X_MPCORE_SYNCPT, dev);
/* disable the ip_busy_timeout. this prevents write drops, etc.
* there's no real way to recover from a hung client anyway.
*/
- writel(0, sync_regs + HOST1X_SYNC_IP_BUSY_TIMEOUT);
+ writel(0, sync_regs + host1x_sync_ip_busy_timeout_r());
/* increase the auto-ack timout to the maximum value. 2d will hang
* otherwise on ap20.
*/
- writel(0xff, sync_regs + HOST1X_SYNC_CTXSW_TIMEOUT_CFG);
+ writel(0xff, sync_regs + host1x_sync_ctxsw_timeout_cfg_r());
}
static void t20_intr_set_host_clocks_per_usec(struct nvhost_intr *intr, u32 cpm)
@@ -48,7 +108,7 @@ static void t20_intr_set_host_clocks_per_usec(struct nvhost_intr *intr, u32 cpm)
struct nvhost_master *dev = intr_to_dev(intr);
void __iomem *sync_regs = dev->sync_aperture;
/* write microsecond clock register */
- writel(cpm, sync_regs + HOST1X_SYNC_USEC_CLK);
+ writel(cpm, sync_regs + host1x_sync_usec_clk_r());
}
static void t20_intr_set_syncpt_threshold(struct nvhost_intr *intr,
@@ -57,35 +117,46 @@ static void t20_intr_set_syncpt_threshold(struct nvhost_intr *intr,
struct nvhost_master *dev = intr_to_dev(intr);
void __iomem *sync_regs = dev->sync_aperture;
thresh &= 0xffff;
- writel(thresh, sync_regs + (HOST1X_SYNC_SYNCPT_INT_THRESH_0 + id * 4));
+ writel(thresh, sync_regs +
+ (host1x_sync_syncpt_int_thresh_0_r() + id * REGISTER_STRIDE));
}
static void t20_intr_enable_syncpt_intr(struct nvhost_intr *intr, u32 id)
{
struct nvhost_master *dev = intr_to_dev(intr);
void __iomem *sync_regs = dev->sync_aperture;
- writel(BIT(id), sync_regs + HOST1X_SYNC_SYNCPT_THRESH_INT_ENABLE_CPU0);
+
+ writel(BIT_MASK(id), sync_regs +
+ host1x_sync_syncpt_thresh_int_enable_cpu0_r() +
+ BIT_WORD(id) * REGISTER_STRIDE);
}
static void t20_intr_disable_all_syncpt_intrs(struct nvhost_intr *intr)
{
struct nvhost_master *dev = intr_to_dev(intr);
void __iomem *sync_regs = dev->sync_aperture;
- /* disable interrupts for both cpu's */
- writel(0, sync_regs + HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE);
-
- /* clear status for both cpu's */
- writel(0xffffffffu, sync_regs +
- HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS);
- writel(0xffffffffu, sync_regs +
- HOST1X_SYNC_SYNCPT_THRESH_CPU1_INT_STATUS);
+ u32 reg;
+
+ for (reg = 0; reg <= BIT_WORD(dev->info.nb_pts) * REGISTER_STRIDE;
+ reg += REGISTER_STRIDE) {
+ /* disable interrupts for both cpu's */
+ writel(0, sync_regs +
+ host1x_sync_syncpt_thresh_int_disable_r() +
+ reg);
+
+ /* clear status for both cpu's */
+ writel(0xffffffffu, sync_regs +
+ host1x_sync_syncpt_thresh_cpu0_int_status_r() + reg);
+ writel(0xffffffffu, sync_regs +
+ host1x_sync_syncpt_thresh_cpu1_int_status_r() + reg);
+ }
}
/**
* Sync point threshold interrupt service function
* Handles sync point threshold triggers, in interrupt context
*/
-irqreturn_t t20_intr_syncpt_thresh_isr(int irq, void *dev_id)
+static irqreturn_t t20_intr_syncpt_thresh_isr(int irq, void *dev_id)
{
struct nvhost_intr_syncpt *syncpt = dev_id;
unsigned int id = syncpt->id;
@@ -93,10 +164,12 @@ irqreturn_t t20_intr_syncpt_thresh_isr(int irq, void *dev_id)
void __iomem *sync_regs = intr_to_dev(intr)->sync_aperture;
- writel(BIT(id),
- sync_regs + HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE);
- writel(BIT(id),
- sync_regs + HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS);
+ u32 reg = BIT_WORD(id) * REGISTER_STRIDE;
+
+ writel(BIT_MASK(id), sync_regs +
+ host1x_sync_syncpt_thresh_int_disable_r() + reg);
+ writel(BIT_MASK(id), sync_regs +
+ host1x_sync_syncpt_thresh_cpu0_int_status_r() + reg);
return IRQ_WAKE_THREAD;
}
@@ -113,21 +186,21 @@ static irqreturn_t t20_intr_host1x_isr(int irq, void *dev_id)
u32 ext_stat;
u32 addr;
- stat = readl(sync_regs + HOST1X_SYNC_HINTSTATUS);
- ext_stat = readl(sync_regs + HOST1X_SYNC_HINTSTATUS_EXT);
+ stat = readl(sync_regs + host1x_sync_hintstatus_r());
+ ext_stat = readl(sync_regs + host1x_sync_hintstatus_ext_r());
- if (HOST1X_VAL(SYNC_HINTSTATUS_EXT, IP_READ_INT, ext_stat)) {
- addr = readl(sync_regs + HOST1X_SYNC_IP_READ_TIMEOUT_ADDR);
+ if (host1x_sync_hintstatus_ext_ip_read_int_v(ext_stat)) {
+ addr = readl(sync_regs + host1x_sync_ip_read_timeout_addr_r());
pr_err("Host read timeout at address %x\n", addr);
}
- if (HOST1X_VAL(SYNC_HINTSTATUS_EXT, IP_WRITE_INT, ext_stat)) {
- addr = readl(sync_regs + HOST1X_SYNC_IP_WRITE_TIMEOUT_ADDR);
+ if (host1x_sync_hintstatus_ext_ip_write_int_v(ext_stat)) {
+ addr = readl(sync_regs + host1x_sync_ip_write_timeout_addr_r());
pr_err("Host write timeout at address %x\n", addr);
}
- writel(ext_stat, sync_regs + HOST1X_SYNC_HINTSTATUS_EXT);
- writel(stat, sync_regs + HOST1X_SYNC_HINTSTATUS);
+ writel(ext_stat, sync_regs + host1x_sync_hintstatus_ext_r());
+ writel(stat, sync_regs + host1x_sync_hintstatus_r());
return IRQ_HANDLED;
}
@@ -140,11 +213,11 @@ static int t20_intr_request_host_general_irq(struct nvhost_intr *intr)
return 0;
/* master disable for general (not syncpt) host interrupts */
- writel(0, sync_regs + HOST1X_SYNC_INTMASK);
+ writel(0, sync_regs + host1x_sync_intmask_r());
/* clear status & extstatus */
- writel(0xfffffffful, sync_regs + HOST1X_SYNC_HINTSTATUS_EXT);
- writel(0xfffffffful, sync_regs + HOST1X_SYNC_HINTSTATUS);
+ writel(0xfffffffful, sync_regs + host1x_sync_hintstatus_ext_r());
+ writel(0xfffffffful, sync_regs + host1x_sync_hintstatus_r());
err = request_irq(intr->host_general_irq, t20_intr_host1x_isr, 0,
"host_status", intr);
@@ -152,16 +225,16 @@ static int t20_intr_request_host_general_irq(struct nvhost_intr *intr)
return err;
/* enable extra interrupt sources IP_READ_INT and IP_WRITE_INT */
- writel(BIT(30) | BIT(31), sync_regs + HOST1X_SYNC_HINTMASK_EXT);
+ writel(BIT(30) | BIT(31), sync_regs + host1x_sync_hintmask_ext_r());
/* enable extra interrupt sources */
- writel(BIT(31), sync_regs + HOST1X_SYNC_HINTMASK);
+ writel(BIT(31), sync_regs + host1x_sync_hintmask_r());
/* enable host module interrupt to CPU0 */
- writel(BIT(0), sync_regs + HOST1X_SYNC_INTC0MASK);
+ writel(BIT(0), sync_regs + host1x_sync_intc0mask_r());
/* master enable for general (not syncpt) host interrupts */
- writel(BIT(0), sync_regs + HOST1X_SYNC_INTMASK);
+ writel(BIT(0), sync_regs + host1x_sync_intmask_r());
intr->host_general_irq_requested = true;
@@ -174,7 +247,7 @@ static void t20_intr_free_host_general_irq(struct nvhost_intr *intr)
void __iomem *sync_regs = intr_to_dev(intr)->sync_aperture;
/* master disable for general (not syncpt) host interrupts */
- writel(0, sync_regs + HOST1X_SYNC_INTMASK);
+ writel(0, sync_regs + host1x_sync_intmask_r());
free_irq(intr->host_general_irq, intr);
intr->host_general_irq_requested = false;
@@ -198,21 +271,13 @@ static int t20_request_syncpt_irq(struct nvhost_intr_syncpt *syncpt)
return 0;
}
-int nvhost_init_t20_intr_support(struct nvhost_master *host)
-{
- host->op.intr.init_host_sync = t20_intr_init_host_sync;
- host->op.intr.set_host_clocks_per_usec =
- t20_intr_set_host_clocks_per_usec;
- host->op.intr.set_syncpt_threshold = t20_intr_set_syncpt_threshold;
- host->op.intr.enable_syncpt_intr = t20_intr_enable_syncpt_intr;
- host->op.intr.disable_all_syncpt_intrs =
- t20_intr_disable_all_syncpt_intrs;
- host->op.intr.request_host_general_irq =
- t20_intr_request_host_general_irq;
- host->op.intr.free_host_general_irq =
- t20_intr_free_host_general_irq;
- host->op.intr.request_syncpt_irq =
- t20_request_syncpt_irq;
-
- return 0;
-}
+static const struct nvhost_intr_ops host1x_intr_ops = {
+ .init_host_sync = t20_intr_init_host_sync,
+ .set_host_clocks_per_usec = t20_intr_set_host_clocks_per_usec,
+ .set_syncpt_threshold = t20_intr_set_syncpt_threshold,
+ .enable_syncpt_intr = t20_intr_enable_syncpt_intr,
+ .disable_all_syncpt_intrs = t20_intr_disable_all_syncpt_intrs,
+ .request_host_general_irq = t20_intr_request_host_general_irq,
+ .free_host_general_irq = t20_intr_free_host_general_irq,
+ .request_syncpt_irq = t20_request_syncpt_irq,
+};
diff --git a/drivers/video/tegra/host/host1x/host1x_syncpt.c b/drivers/video/tegra/host/host1x/host1x_syncpt.c
index b431fa350638..8cca9dbbbc08 100644
--- a/drivers/video/tegra/host/host1x/host1x_syncpt.c
+++ b/drivers/video/tegra/host/host1x/host1x_syncpt.c
@@ -19,10 +19,12 @@
*/
#include <linux/nvhost_ioctl.h>
+#include <linux/io.h>
+#include <trace/events/nvhost.h>
#include "nvhost_syncpt.h"
-#include "dev.h"
-#include "host1x_syncpt.h"
-#include "host1x_hardware.h"
+#include "nvhost_acm.h"
+#include "host1x.h"
+#include "chip_support.h"
/**
* Write the current syncpoint value back to hw.
@@ -31,7 +33,7 @@ static void t20_syncpt_reset(struct nvhost_syncpt *sp, u32 id)
{
struct nvhost_master *dev = syncpt_to_dev(sp);
int min = nvhost_syncpt_read_min(sp, id);
- writel(min, dev->sync_aperture + (HOST1X_SYNC_SYNCPT_0 + id * 4));
+ writel(min, dev->sync_aperture + (host1x_sync_syncpt_0_r() + id * 4));
}
/**
@@ -41,7 +43,7 @@ static void t20_syncpt_reset_wait_base(struct nvhost_syncpt *sp, u32 id)
{
struct nvhost_master *dev = syncpt_to_dev(sp);
writel(sp->base_val[id],
- dev->sync_aperture + (HOST1X_SYNC_SYNCPT_BASE_0 + id * 4));
+ dev->sync_aperture + (host1x_sync_syncpt_base_0_r() + id * 4));
}
/**
@@ -51,7 +53,7 @@ static void t20_syncpt_read_wait_base(struct nvhost_syncpt *sp, u32 id)
{
struct nvhost_master *dev = syncpt_to_dev(sp);
sp->base_val[id] = readl(dev->sync_aperture +
- (HOST1X_SYNC_SYNCPT_BASE_0 + id * 4));
+ (host1x_sync_syncpt_base_0_r() + id * 4));
}
/**
@@ -66,7 +68,7 @@ static u32 t20_syncpt_update_min(struct nvhost_syncpt *sp, u32 id)
do {
old = nvhost_syncpt_read_min(sp, id);
- live = readl(sync_regs + (HOST1X_SYNC_SYNCPT_0 + id * 4));
+ live = readl(sync_regs + (host1x_sync_syncpt_0_r() + id * 4));
} while ((u32)atomic_cmpxchg(&sp->min_val[id], old, live) != old);
if (!nvhost_syncpt_check_max(sp, id, live))
@@ -87,114 +89,55 @@ static u32 t20_syncpt_update_min(struct nvhost_syncpt *sp, u32 id)
static void t20_syncpt_cpu_incr(struct nvhost_syncpt *sp, u32 id)
{
struct nvhost_master *dev = syncpt_to_dev(sp);
+ u32 reg_offset = id / 32;
+
BUG_ON(!nvhost_module_powered(dev->dev));
- if (!client_managed(id) && nvhost_syncpt_min_eq_max(sp, id)) {
+ if (!nvhost_syncpt_client_managed(sp, id)
+ && nvhost_syncpt_min_eq_max(sp, id)) {
dev_err(&syncpt_to_dev(sp)->dev->dev,
"Trying to increment syncpoint id %d beyond max\n",
id);
nvhost_debug_dump(syncpt_to_dev(sp));
return;
}
- writel(BIT(id), dev->sync_aperture + HOST1X_SYNC_SYNCPT_CPU_INCR);
+ writel(BIT_MASK(id), dev->sync_aperture +
+ host1x_sync_syncpt_cpu_incr_r() + reg_offset * 4);
wmb();
}
-/* check for old WAITs to be removed (avoiding a wrap) */
-static int t20_syncpt_wait_check(struct nvhost_syncpt *sp,
- struct nvmap_client *nvmap,
- u32 waitchk_mask,
- struct nvhost_waitchk *wait,
- int num_waitchk)
+/* remove a wait pointed to by patch_addr */
+static int host1x_syncpt_patch_wait(struct nvhost_syncpt *sp,
+ void *patch_addr)
{
- u32 idx;
- int err = 0;
-
- /* get current syncpt values */
- for (idx = 0; idx < NV_HOST1X_SYNCPT_NB_PTS; idx++) {
- if (BIT(idx) & waitchk_mask)
- nvhost_syncpt_update_min(sp, idx);
- }
-
- BUG_ON(!wait && !num_waitchk);
-
- /* compare syncpt vs wait threshold */
- while (num_waitchk) {
- u32 override;
-
- BUG_ON(wait->syncpt_id >= NV_HOST1X_SYNCPT_NB_PTS);
- if (nvhost_syncpt_is_expired(sp,
- wait->syncpt_id, wait->thresh)) {
- /*
- * NULL an already satisfied WAIT_SYNCPT host method,
- * by patching its args in the command stream. The
- * method data is changed to reference a reserved
- * (never given out or incr) NVSYNCPT_GRAPHICS_HOST
- * syncpt with a matching threshold value of 0, so
- * is guaranteed to be popped by the host HW.
- */
- dev_dbg(&syncpt_to_dev(sp)->dev->dev,
- "drop WAIT id %d (%s) thresh 0x%x, min 0x%x\n",
- wait->syncpt_id,
- syncpt_op(sp).name(sp, wait->syncpt_id),
- wait->thresh,
- nvhost_syncpt_read_min(sp, wait->syncpt_id));
-
- /* patch the wait */
- override = nvhost_class_host_wait_syncpt(
- NVSYNCPT_GRAPHICS_HOST, 0);
- err = nvmap_patch_word(nvmap,
- (struct nvmap_handle *)wait->mem,
- wait->offset, override);
- if (err)
- break;
- }
-
- wait++;
- num_waitchk--;
- }
- return err;
+ u32 override = nvhost_class_host_wait_syncpt(
+ NVSYNCPT_GRAPHICS_HOST, 0);
+ __raw_writel(override, patch_addr);
+ return 0;
}
-static const char *s_syncpt_names[32] = {
- "gfx_host",
- "", "", "", "", "", "", "",
- "disp0_a", "disp1_a", "avp_0",
- "csi_vi_0", "csi_vi_1",
- "vi_isp_0", "vi_isp_1", "vi_isp_2", "vi_isp_3", "vi_isp_4",
- "2d_0", "2d_1",
- "disp0_b", "disp1_b",
- "3d",
- "mpe",
- "disp0_c", "disp1_c",
- "vblank0", "vblank1",
- "mpe_ebm_eof", "mpe_wr_safe",
- "2d_tinyblt",
- "dsi"
-};
-
-static const char *t20_syncpt_name(struct nvhost_syncpt *s, u32 id)
+static const char *t20_syncpt_name(struct nvhost_syncpt *sp, u32 id)
{
- BUG_ON(id >= ARRAY_SIZE(s_syncpt_names));
- return s_syncpt_names[id];
+ struct host1x_device_info *info = &syncpt_to_dev(sp)->info;
+ return (id >= info->nb_pts) ? NULL : info->syncpt_names[id];
}
static void t20_syncpt_debug(struct nvhost_syncpt *sp)
{
u32 i;
- for (i = 0; i < NV_HOST1X_SYNCPT_NB_PTS; i++) {
+ for (i = 0; i < nvhost_syncpt_nb_pts(sp); i++) {
u32 max = nvhost_syncpt_read_max(sp, i);
u32 min = nvhost_syncpt_update_min(sp, i);
if (!max && !min)
continue;
dev_info(&syncpt_to_dev(sp)->dev->dev,
"id %d (%s) min %d max %d\n",
- i, syncpt_op(sp).name(sp, i),
+ i, syncpt_op().name(sp, i),
min, max);
}
- for (i = 0; i < NV_HOST1X_SYNCPT_NB_BASES; i++) {
+ for (i = 0; i < nvhost_syncpt_nb_bases(sp); i++) {
u32 base_val;
t20_syncpt_read_wait_base(sp, i);
base_val = sp->base_val[i];
@@ -212,7 +155,7 @@ static int syncpt_mutex_try_lock(struct nvhost_syncpt *sp,
void __iomem *sync_regs = syncpt_to_dev(sp)->sync_aperture;
/* mlock registers returns 0 when the lock is aquired.
* writing 0 clears the lock. */
- return !!readl(sync_regs + (HOST1X_SYNC_MLOCK_0 + idx * 4));
+ return !!readl(sync_regs + (host1x_sync_mlock_0_r() + idx * 4));
}
static void syncpt_mutex_unlock(struct nvhost_syncpt *sp,
@@ -220,31 +163,18 @@ static void syncpt_mutex_unlock(struct nvhost_syncpt *sp,
{
void __iomem *sync_regs = syncpt_to_dev(sp)->sync_aperture;
- writel(0, sync_regs + (HOST1X_SYNC_MLOCK_0 + idx * 4));
+ writel(0, sync_regs + (host1x_sync_mlock_0_r() + idx * 4));
}
-int host1x_init_syncpt_support(struct nvhost_master *host)
-{
-
- host->sync_aperture = host->aperture +
- (NV_HOST1X_CHANNEL0_BASE +
- HOST1X_CHANNEL_SYNC_REG_BASE);
-
- host->op.syncpt.reset = t20_syncpt_reset;
- host->op.syncpt.reset_wait_base = t20_syncpt_reset_wait_base;
- host->op.syncpt.read_wait_base = t20_syncpt_read_wait_base;
- host->op.syncpt.update_min = t20_syncpt_update_min;
- host->op.syncpt.cpu_incr = t20_syncpt_cpu_incr;
- host->op.syncpt.wait_check = t20_syncpt_wait_check;
- host->op.syncpt.debug = t20_syncpt_debug;
- host->op.syncpt.name = t20_syncpt_name;
- host->op.syncpt.mutex_try_lock = syncpt_mutex_try_lock;
- host->op.syncpt.mutex_unlock = syncpt_mutex_unlock;
-
- host->syncpt.nb_pts = NV_HOST1X_SYNCPT_NB_PTS;
- host->syncpt.nb_bases = NV_HOST1X_SYNCPT_NB_BASES;
- host->syncpt.client_managed = NVSYNCPTS_CLIENT_MANAGED;
- host->syncpt.nb_mlocks = NV_HOST1X_SYNC_MLOCK_NUM;
-
- return 0;
-}
+static const struct nvhost_syncpt_ops host1x_syncpt_ops = {
+ .reset = t20_syncpt_reset,
+ .reset_wait_base = t20_syncpt_reset_wait_base,
+ .read_wait_base = t20_syncpt_read_wait_base,
+ .update_min = t20_syncpt_update_min,
+ .cpu_incr = t20_syncpt_cpu_incr,
+ .patch_wait = host1x_syncpt_patch_wait,
+ .debug = t20_syncpt_debug,
+ .name = t20_syncpt_name,
+ .mutex_try_lock = syncpt_mutex_try_lock,
+ .mutex_unlock = syncpt_mutex_unlock,
+};
diff --git a/drivers/video/tegra/host/host1x/host1x_syncpt.h b/drivers/video/tegra/host/host1x/host1x_syncpt.h
index 0d263dc92ed5..a971db8b1d94 100644
--- a/drivers/video/tegra/host/host1x/host1x_syncpt.h
+++ b/drivers/video/tegra/host/host1x/host1x_syncpt.h
@@ -21,9 +21,12 @@
#ifndef __NVHOST_HOST1X_HOST1X_SYNCPT_H
#define __NVHOST_HOST1X_HOST1X_SYNCPT_H
-#define NVSYNCPT_DISP0_A (8)
-#define NVSYNCPT_DISP1_A (9)
-#define NVSYNCPT_AVP_0 (10)
+/* FIXME:
+ * Sync point ids are now split into 2 files.
+ * 1 if this one and other is in include/linux/nvhost.h
+ * So if someone decides to add new sync point in future
+ * please check both the header files
+ */
#define NVSYNCPT_CSI_VI_0 (11)
#define NVSYNCPT_CSI_VI_1 (12)
#define NVSYNCPT_VI_ISP_0 (13)
@@ -33,23 +36,10 @@
#define NVSYNCPT_VI_ISP_4 (17)
#define NVSYNCPT_2D_0 (18)
#define NVSYNCPT_2D_1 (19)
-#define NVSYNCPT_DISP0_B (20)
-#define NVSYNCPT_DISP1_B (21)
#define NVSYNCPT_3D (22)
#define NVSYNCPT_MPE (23)
-#define NVSYNCPT_DISP0_C (24)
-#define NVSYNCPT_DISP1_C (25)
-#define NVSYNCPT_VBLANK0 (26)
-#define NVSYNCPT_VBLANK1 (27)
#define NVSYNCPT_MPE_EBM_EOF (28)
#define NVSYNCPT_MPE_WR_SAFE (29)
-#define NVSYNCPT_DSI (31)
-
-
-/*#define NVSYNCPT_2D_CHANNEL2_0 (20) */
-/*#define NVSYNCPT_2D_CHANNEL2_1 (21) */
-/*#define NVSYNCPT_2D_TINYBLT_WAR (30)*/
-/*#define NVSYNCPT_2D_TINYBLT_RESTORE_CLASS_ID (30)*/
/* sync points that are wholly managed by the client */
#define NVSYNCPTS_CLIENT_MANAGED ( \
@@ -64,14 +54,9 @@
BIT(NVSYNCPT_MPE_EBM_EOF) | BIT(NVSYNCPT_MPE_WR_SAFE) | \
BIT(NVSYNCPT_2D_1) | BIT(NVSYNCPT_AVP_0))
-
#define NVWAITBASE_2D_0 (1)
#define NVWAITBASE_2D_1 (2)
#define NVWAITBASE_3D (3)
#define NVWAITBASE_MPE (4)
-struct nvhost_master;
-int host1x_init_syncpt(struct nvhost_master *host);
-int host1x_init_syncpt_support(struct nvhost_master *host);
-
#endif
diff --git a/drivers/video/tegra/host/host1x/hw_host1x01_channel.h b/drivers/video/tegra/host/host1x/hw_host1x01_channel.h
new file mode 100644
index 000000000000..ca2f9a0778cd
--- /dev/null
+++ b/drivers/video/tegra/host/host1x/hw_host1x01_channel.h
@@ -0,0 +1,182 @@
+/*
+ * drivers/video/tegra/host/host1x/hw_host1x_channel_host1x.h
+ *
+ * Copyright (c) 2012, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+ /*
+ * Function naming determines intended use:
+ *
+ * <x>_r(void) : Returns the offset for register <x>.
+ *
+ * <x>_w(void) : Returns the word offset for word (4 byte) element <x>.
+ *
+ * <x>_<y>_s(void) : Returns size of field <y> of register <x> in bits.
+ *
+ * <x>_<y>_f(u32 v) : Returns a value based on 'v' which has been shifted
+ * and masked to place it at field <y> of register <x>. This value
+ * can be |'d with others to produce a full register value for
+ * register <x>.
+ *
+ * <x>_<y>_m(void) : Returns a mask for field <y> of register <x>. This
+ * value can be ~'d and then &'d to clear the value of field <y> for
+ * register <x>.
+ *
+ * <x>_<y>_<z>_f(void) : Returns the constant value <z> after being shifted
+ * to place it at field <y> of register <x>. This value can be |'d
+ * with others to produce a full register value for <x>.
+ *
+ * <x>_<y>_v(u32 r) : Returns the value of field <y> from a full register
+ * <x> value 'r' after being shifted to place its LSB at bit 0.
+ * This value is suitable for direct comparison with other unshifted
+ * values appropriate for use in field <y> of register <x>.
+ *
+ * <x>_<y>_<z>_v(void) : Returns the constant value for <z> defined for
+ * field <y> of register <x>. This value is suitable for direct
+ * comparison with unshifted values appropriate for use in field <y>
+ * of register <x>.
+ */
+
+#ifndef __hw_host1x_channel_host1x_h__
+#define __hw_host1x_channel_host1x_h__
+/*This file is autogenerated. Do not edit. */
+
+static inline u32 host1x_channel_fifostat_r(void)
+{
+ return 0x0;
+}
+static inline u32 host1x_channel_fifostat_cfempty_s(void)
+{
+ return 1;
+}
+static inline u32 host1x_channel_fifostat_cfempty_f(u32 v)
+{
+ return (v & 0x1) << 10;
+}
+static inline u32 host1x_channel_fifostat_cfempty_m(void)
+{
+ return 0x1 << 10;
+}
+static inline u32 host1x_channel_fifostat_cfempty_v(u32 r)
+{
+ return (r >> 10) & 0x1;
+}
+static inline u32 host1x_channel_fifostat_cfempty_notempty_v(void)
+{
+ return 0;
+}
+static inline u32 host1x_channel_fifostat_cfempty_empty_v(void)
+{
+ return 1;
+}
+static inline u32 host1x_channel_fifostat_outfentries_s(void)
+{
+ return 5;
+}
+static inline u32 host1x_channel_fifostat_outfentries_f(u32 v)
+{
+ return (v & 0x1f) << 24;
+}
+static inline u32 host1x_channel_fifostat_outfentries_m(void)
+{
+ return 0x1f << 24;
+}
+static inline u32 host1x_channel_fifostat_outfentries_v(u32 r)
+{
+ return (r >> 24) & 0x1f;
+}
+static inline u32 host1x_channel_inddata_r(void)
+{
+ return 0xc;
+}
+static inline u32 host1x_channel_dmastart_r(void)
+{
+ return 0x14;
+}
+static inline u32 host1x_channel_dmaput_r(void)
+{
+ return 0x18;
+}
+static inline u32 host1x_channel_dmaget_r(void)
+{
+ return 0x1c;
+}
+static inline u32 host1x_channel_dmaend_r(void)
+{
+ return 0x20;
+}
+static inline u32 host1x_channel_dmactrl_r(void)
+{
+ return 0x24;
+}
+static inline u32 host1x_channel_dmactrl_dmastop_s(void)
+{
+ return 1;
+}
+static inline u32 host1x_channel_dmactrl_dmastop_f(u32 v)
+{
+ return (v & 0x1) << 0;
+}
+static inline u32 host1x_channel_dmactrl_dmastop_m(void)
+{
+ return 0x1 << 0;
+}
+static inline u32 host1x_channel_dmactrl_dmastop_v(u32 r)
+{
+ return (r >> 0) & 0x1;
+}
+static inline u32 host1x_channel_dmactrl_dmastop_run_v(void)
+{
+ return 0;
+}
+static inline u32 host1x_channel_dmactrl_dmastop_stop_v(void)
+{
+ return 1;
+}
+static inline u32 host1x_channel_dmactrl_dmagetrst_s(void)
+{
+ return 1;
+}
+static inline u32 host1x_channel_dmactrl_dmagetrst_f(u32 v)
+{
+ return (v & 0x1) << 1;
+}
+static inline u32 host1x_channel_dmactrl_dmagetrst_m(void)
+{
+ return 0x1 << 1;
+}
+static inline u32 host1x_channel_dmactrl_dmagetrst_v(u32 r)
+{
+ return (r >> 1) & 0x1;
+}
+static inline u32 host1x_channel_dmactrl_dmainitget_s(void)
+{
+ return 1;
+}
+static inline u32 host1x_channel_dmactrl_dmainitget_f(u32 v)
+{
+ return (v & 0x1) << 2;
+}
+static inline u32 host1x_channel_dmactrl_dmainitget_m(void)
+{
+ return 0x1 << 2;
+}
+static inline u32 host1x_channel_dmactrl_dmainitget_v(u32 r)
+{
+ return (r >> 2) & 0x1;
+}
+
+#endif /* __hw_host1x_channel_host1x_h__ */
diff --git a/drivers/video/tegra/host/host1x/hw_host1x01_sync.h b/drivers/video/tegra/host/host1x/hw_host1x01_sync.h
new file mode 100644
index 000000000000..67f0cbfb85b9
--- /dev/null
+++ b/drivers/video/tegra/host/host1x/hw_host1x01_sync.h
@@ -0,0 +1,398 @@
+/*
+ * drivers/video/tegra/host/host1x/hw_host1x_sync_host1x.h
+ *
+ * Copyright (c) 2012, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+ /*
+ * Function naming determines intended use:
+ *
+ * <x>_r(void) : Returns the offset for register <x>.
+ *
+ * <x>_w(void) : Returns the word offset for word (4 byte) element <x>.
+ *
+ * <x>_<y>_s(void) : Returns size of field <y> of register <x> in bits.
+ *
+ * <x>_<y>_f(u32 v) : Returns a value based on 'v' which has been shifted
+ * and masked to place it at field <y> of register <x>. This value
+ * can be |'d with others to produce a full register value for
+ * register <x>.
+ *
+ * <x>_<y>_m(void) : Returns a mask for field <y> of register <x>. This
+ * value can be ~'d and then &'d to clear the value of field <y> for
+ * register <x>.
+ *
+ * <x>_<y>_<z>_f(void) : Returns the constant value <z> after being shifted
+ * to place it at field <y> of register <x>. This value can be |'d
+ * with others to produce a full register value for <x>.
+ *
+ * <x>_<y>_v(u32 r) : Returns the value of field <y> from a full register
+ * <x> value 'r' after being shifted to place its LSB at bit 0.
+ * This value is suitable for direct comparison with other unshifted
+ * values appropriate for use in field <y> of register <x>.
+ *
+ * <x>_<y>_<z>_v(void) : Returns the constant value for <z> defined for
+ * field <y> of register <x>. This value is suitable for direct
+ * comparison with unshifted values appropriate for use in field <y>
+ * of register <x>.
+ */
+
+#ifndef __hw_host1x_sync_host1x_h__
+#define __hw_host1x_sync_host1x_h__
+/*This file is autogenerated. Do not edit. */
+
+static inline u32 host1x_sync_intmask_r(void)
+{
+ return 0x4;
+}
+static inline u32 host1x_sync_intc0mask_r(void)
+{
+ return 0x8;
+}
+static inline u32 host1x_sync_hintstatus_r(void)
+{
+ return 0x20;
+}
+static inline u32 host1x_sync_hintmask_r(void)
+{
+ return 0x24;
+}
+static inline u32 host1x_sync_hintstatus_ext_r(void)
+{
+ return 0x28;
+}
+static inline u32 host1x_sync_hintstatus_ext_ip_read_int_s(void)
+{
+ return 1;
+}
+static inline u32 host1x_sync_hintstatus_ext_ip_read_int_f(u32 v)
+{
+ return (v & 0x1) << 30;
+}
+static inline u32 host1x_sync_hintstatus_ext_ip_read_int_m(void)
+{
+ return 0x1 << 30;
+}
+static inline u32 host1x_sync_hintstatus_ext_ip_read_int_v(u32 r)
+{
+ return (r >> 30) & 0x1;
+}
+static inline u32 host1x_sync_hintstatus_ext_ip_write_int_s(void)
+{
+ return 1;
+}
+static inline u32 host1x_sync_hintstatus_ext_ip_write_int_f(u32 v)
+{
+ return (v & 0x1) << 31;
+}
+static inline u32 host1x_sync_hintstatus_ext_ip_write_int_m(void)
+{
+ return 0x1 << 31;
+}
+static inline u32 host1x_sync_hintstatus_ext_ip_write_int_v(u32 r)
+{
+ return (r >> 31) & 0x1;
+}
+static inline u32 host1x_sync_hintmask_ext_r(void)
+{
+ return 0x2c;
+}
+static inline u32 host1x_sync_syncpt_thresh_cpu0_int_status_r(void)
+{
+ return 0x40;
+}
+static inline u32 host1x_sync_syncpt_thresh_cpu1_int_status_r(void)
+{
+ return 0x48;
+}
+static inline u32 host1x_sync_syncpt_thresh_int_disable_r(void)
+{
+ return 0x60;
+}
+static inline u32 host1x_sync_syncpt_thresh_int_enable_cpu0_r(void)
+{
+ return 0x68;
+}
+static inline u32 host1x_sync_cf0_setup_r(void)
+{
+ return 0x80;
+}
+static inline u32 host1x_sync_cf0_setup_cf0_base_s(void)
+{
+ return 9;
+}
+static inline u32 host1x_sync_cf0_setup_cf0_base_f(u32 v)
+{
+ return (v & 0x1ff) << 0;
+}
+static inline u32 host1x_sync_cf0_setup_cf0_base_m(void)
+{
+ return 0x1ff << 0;
+}
+static inline u32 host1x_sync_cf0_setup_cf0_base_v(u32 r)
+{
+ return (r >> 0) & 0x1ff;
+}
+static inline u32 host1x_sync_cf0_setup_cf0_limit_s(void)
+{
+ return 9;
+}
+static inline u32 host1x_sync_cf0_setup_cf0_limit_f(u32 v)
+{
+ return (v & 0x1ff) << 16;
+}
+static inline u32 host1x_sync_cf0_setup_cf0_limit_m(void)
+{
+ return 0x1ff << 16;
+}
+static inline u32 host1x_sync_cf0_setup_cf0_limit_v(u32 r)
+{
+ return (r >> 16) & 0x1ff;
+}
+static inline u32 host1x_sync_cmdproc_stop_r(void)
+{
+ return 0xac;
+}
+static inline u32 host1x_sync_ch_teardown_r(void)
+{
+ return 0xb0;
+}
+static inline u32 host1x_sync_usec_clk_r(void)
+{
+ return 0x1a4;
+}
+static inline u32 host1x_sync_ctxsw_timeout_cfg_r(void)
+{
+ return 0x1a8;
+}
+static inline u32 host1x_sync_ip_busy_timeout_r(void)
+{
+ return 0x1bc;
+}
+static inline u32 host1x_sync_ip_read_timeout_addr_r(void)
+{
+ return 0x1c0;
+}
+static inline u32 host1x_sync_ip_write_timeout_addr_r(void)
+{
+ return 0x1c4;
+}
+static inline u32 host1x_sync_mlock_0_r(void)
+{
+ return 0x2c0;
+}
+static inline u32 host1x_sync_mlock_owner_0_r(void)
+{
+ return 0x340;
+}
+static inline u32 host1x_sync_mlock_owner_0_mlock_owner_chid_0_s(void)
+{
+ return 4;
+}
+static inline u32 host1x_sync_mlock_owner_0_mlock_owner_chid_0_f(u32 v)
+{
+ return (v & 0xf) << 8;
+}
+static inline u32 host1x_sync_mlock_owner_0_mlock_owner_chid_0_m(void)
+{
+ return 0xf << 8;
+}
+static inline u32 host1x_sync_mlock_owner_0_mlock_owner_chid_0_v(u32 r)
+{
+ return (r >> 8) & 0xf;
+}
+static inline u32 host1x_sync_mlock_owner_0_mlock_cpu_owns_0_s(void)
+{
+ return 1;
+}
+static inline u32 host1x_sync_mlock_owner_0_mlock_cpu_owns_0_f(u32 v)
+{
+ return (v & 0x1) << 1;
+}
+static inline u32 host1x_sync_mlock_owner_0_mlock_cpu_owns_0_m(void)
+{
+ return 0x1 << 1;
+}
+static inline u32 host1x_sync_mlock_owner_0_mlock_cpu_owns_0_v(u32 r)
+{
+ return (r >> 1) & 0x1;
+}
+static inline u32 host1x_sync_mlock_owner_0_mlock_ch_owns_0_s(void)
+{
+ return 1;
+}
+static inline u32 host1x_sync_mlock_owner_0_mlock_ch_owns_0_f(u32 v)
+{
+ return (v & 0x1) << 0;
+}
+static inline u32 host1x_sync_mlock_owner_0_mlock_ch_owns_0_m(void)
+{
+ return 0x1 << 0;
+}
+static inline u32 host1x_sync_mlock_owner_0_mlock_ch_owns_0_v(u32 r)
+{
+ return (r >> 0) & 0x1;
+}
+static inline u32 host1x_sync_syncpt_0_r(void)
+{
+ return 0x400;
+}
+static inline u32 host1x_sync_syncpt_int_thresh_0_r(void)
+{
+ return 0x500;
+}
+static inline u32 host1x_sync_syncpt_base_0_r(void)
+{
+ return 0x600;
+}
+static inline u32 host1x_sync_syncpt_cpu_incr_r(void)
+{
+ return 0x700;
+}
+static inline u32 host1x_sync_cbread0_r(void)
+{
+ return 0x720;
+}
+static inline u32 host1x_sync_cfpeek_ctrl_r(void)
+{
+ return 0x74c;
+}
+static inline u32 host1x_sync_cfpeek_ctrl_cfpeek_addr_s(void)
+{
+ return 9;
+}
+static inline u32 host1x_sync_cfpeek_ctrl_cfpeek_addr_f(u32 v)
+{
+ return (v & 0x1ff) << 0;
+}
+static inline u32 host1x_sync_cfpeek_ctrl_cfpeek_addr_m(void)
+{
+ return 0x1ff << 0;
+}
+static inline u32 host1x_sync_cfpeek_ctrl_cfpeek_addr_v(u32 r)
+{
+ return (r >> 0) & 0x1ff;
+}
+static inline u32 host1x_sync_cfpeek_ctrl_cfpeek_channr_s(void)
+{
+ return 3;
+}
+static inline u32 host1x_sync_cfpeek_ctrl_cfpeek_channr_f(u32 v)
+{
+ return (v & 0x7) << 16;
+}
+static inline u32 host1x_sync_cfpeek_ctrl_cfpeek_channr_m(void)
+{
+ return 0x7 << 16;
+}
+static inline u32 host1x_sync_cfpeek_ctrl_cfpeek_channr_v(u32 r)
+{
+ return (r >> 16) & 0x7;
+}
+static inline u32 host1x_sync_cfpeek_ctrl_cfpeek_ena_s(void)
+{
+ return 1;
+}
+static inline u32 host1x_sync_cfpeek_ctrl_cfpeek_ena_f(u32 v)
+{
+ return (v & 0x1) << 31;
+}
+static inline u32 host1x_sync_cfpeek_ctrl_cfpeek_ena_m(void)
+{
+ return 0x1 << 31;
+}
+static inline u32 host1x_sync_cfpeek_ctrl_cfpeek_ena_v(u32 r)
+{
+ return (r >> 31) & 0x1;
+}
+static inline u32 host1x_sync_cfpeek_read_r(void)
+{
+ return 0x750;
+}
+static inline u32 host1x_sync_cfpeek_ptrs_r(void)
+{
+ return 0x754;
+}
+static inline u32 host1x_sync_cfpeek_ptrs_cf_rd_ptr_s(void)
+{
+ return 9;
+}
+static inline u32 host1x_sync_cfpeek_ptrs_cf_rd_ptr_f(u32 v)
+{
+ return (v & 0x1ff) << 0;
+}
+static inline u32 host1x_sync_cfpeek_ptrs_cf_rd_ptr_m(void)
+{
+ return 0x1ff << 0;
+}
+static inline u32 host1x_sync_cfpeek_ptrs_cf_rd_ptr_v(u32 r)
+{
+ return (r >> 0) & 0x1ff;
+}
+static inline u32 host1x_sync_cfpeek_ptrs_cf_wr_ptr_s(void)
+{
+ return 9;
+}
+static inline u32 host1x_sync_cfpeek_ptrs_cf_wr_ptr_f(u32 v)
+{
+ return (v & 0x1ff) << 16;
+}
+static inline u32 host1x_sync_cfpeek_ptrs_cf_wr_ptr_m(void)
+{
+ return 0x1ff << 16;
+}
+static inline u32 host1x_sync_cfpeek_ptrs_cf_wr_ptr_v(u32 r)
+{
+ return (r >> 16) & 0x1ff;
+}
+static inline u32 host1x_sync_cbstat_0_r(void)
+{
+ return 0x758;
+}
+static inline u32 host1x_sync_cbstat_0_cboffset0_s(void)
+{
+ return 16;
+}
+static inline u32 host1x_sync_cbstat_0_cboffset0_f(u32 v)
+{
+ return (v & 0xffff) << 0;
+}
+static inline u32 host1x_sync_cbstat_0_cboffset0_m(void)
+{
+ return 0xffff << 0;
+}
+static inline u32 host1x_sync_cbstat_0_cboffset0_v(u32 r)
+{
+ return (r >> 0) & 0xffff;
+}
+static inline u32 host1x_sync_cbstat_0_cbclass0_s(void)
+{
+ return 10;
+}
+static inline u32 host1x_sync_cbstat_0_cbclass0_f(u32 v)
+{
+ return (v & 0x3ff) << 16;
+}
+static inline u32 host1x_sync_cbstat_0_cbclass0_m(void)
+{
+ return 0x3ff << 16;
+}
+static inline u32 host1x_sync_cbstat_0_cbclass0_v(u32 r)
+{
+ return (r >> 16) & 0x3ff;
+}
+
+#endif /* __hw_host1x_sync_host1x_h__ */
diff --git a/drivers/video/tegra/host/host1x/hw_host1x01_uclass.h b/drivers/video/tegra/host/host1x/hw_host1x01_uclass.h
new file mode 100644
index 000000000000..ed6e4b706ab9
--- /dev/null
+++ b/drivers/video/tegra/host/host1x/hw_host1x01_uclass.h
@@ -0,0 +1,474 @@
+/*
+ * drivers/video/tegra/host/host1x/hw_host1x_uclass_host1x.h
+ *
+ * Copyright (c) 2012, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+ /*
+ * Function naming determines intended use:
+ *
+ * <x>_r(void) : Returns the offset for register <x>.
+ *
+ * <x>_w(void) : Returns the word offset for word (4 byte) element <x>.
+ *
+ * <x>_<y>_s(void) : Returns size of field <y> of register <x> in bits.
+ *
+ * <x>_<y>_f(u32 v) : Returns a value based on 'v' which has been shifted
+ * and masked to place it at field <y> of register <x>. This value
+ * can be |'d with others to produce a full register value for
+ * register <x>.
+ *
+ * <x>_<y>_m(void) : Returns a mask for field <y> of register <x>. This
+ * value can be ~'d and then &'d to clear the value of field <y> for
+ * register <x>.
+ *
+ * <x>_<y>_<z>_f(void) : Returns the constant value <z> after being shifted
+ * to place it at field <y> of register <x>. This value can be |'d
+ * with others to produce a full register value for <x>.
+ *
+ * <x>_<y>_v(u32 r) : Returns the value of field <y> from a full register
+ * <x> value 'r' after being shifted to place its LSB at bit 0.
+ * This value is suitable for direct comparison with other unshifted
+ * values appropriate for use in field <y> of register <x>.
+ *
+ * <x>_<y>_<z>_v(void) : Returns the constant value for <z> defined for
+ * field <y> of register <x>. This value is suitable for direct
+ * comparison with unshifted values appropriate for use in field <y>
+ * of register <x>.
+ */
+
+#ifndef __hw_host1x_uclass_host1x_h__
+#define __hw_host1x_uclass_host1x_h__
+/*This file is autogenerated. Do not edit. */
+
+static inline u32 host1x_uclass_incr_syncpt_r(void)
+{
+ return 0x0;
+}
+static inline u32 host1x_uclass_incr_syncpt_cond_s(void)
+{
+ return 8;
+}
+static inline u32 host1x_uclass_incr_syncpt_cond_f(u32 v)
+{
+ return (v & 0xff) << 8;
+}
+static inline u32 host1x_uclass_incr_syncpt_cond_m(void)
+{
+ return 0xff << 8;
+}
+static inline u32 host1x_uclass_incr_syncpt_cond_v(u32 r)
+{
+ return (r >> 8) & 0xff;
+}
+static inline u32 host1x_uclass_incr_syncpt_cond_immediate_v(void)
+{
+ return 0;
+}
+static inline u32 host1x_uclass_incr_syncpt_cond_op_done_v(void)
+{
+ return 1;
+}
+static inline u32 host1x_uclass_incr_syncpt_cond_rd_done_v(void)
+{
+ return 2;
+}
+static inline u32 host1x_uclass_incr_syncpt_cond_reg_wr_safe_v(void)
+{
+ return 3;
+}
+static inline u32 host1x_uclass_incr_syncpt_indx_s(void)
+{
+ return 8;
+}
+static inline u32 host1x_uclass_incr_syncpt_indx_f(u32 v)
+{
+ return (v & 0xff) << 0;
+}
+static inline u32 host1x_uclass_incr_syncpt_indx_m(void)
+{
+ return 0xff << 0;
+}
+static inline u32 host1x_uclass_incr_syncpt_indx_v(u32 r)
+{
+ return (r >> 0) & 0xff;
+}
+static inline u32 host1x_uclass_wait_syncpt_r(void)
+{
+ return 0x8;
+}
+static inline u32 host1x_uclass_wait_syncpt_indx_s(void)
+{
+ return 8;
+}
+static inline u32 host1x_uclass_wait_syncpt_indx_f(u32 v)
+{
+ return (v & 0xff) << 24;
+}
+static inline u32 host1x_uclass_wait_syncpt_indx_m(void)
+{
+ return 0xff << 24;
+}
+static inline u32 host1x_uclass_wait_syncpt_indx_v(u32 r)
+{
+ return (r >> 24) & 0xff;
+}
+static inline u32 host1x_uclass_wait_syncpt_thresh_s(void)
+{
+ return 24;
+}
+static inline u32 host1x_uclass_wait_syncpt_thresh_f(u32 v)
+{
+ return (v & 0xffffff) << 0;
+}
+static inline u32 host1x_uclass_wait_syncpt_thresh_m(void)
+{
+ return 0xffffff << 0;
+}
+static inline u32 host1x_uclass_wait_syncpt_thresh_v(u32 r)
+{
+ return (r >> 0) & 0xffffff;
+}
+static inline u32 host1x_uclass_wait_syncpt_base_r(void)
+{
+ return 0x9;
+}
+static inline u32 host1x_uclass_wait_syncpt_base_indx_s(void)
+{
+ return 8;
+}
+static inline u32 host1x_uclass_wait_syncpt_base_indx_f(u32 v)
+{
+ return (v & 0xff) << 24;
+}
+static inline u32 host1x_uclass_wait_syncpt_base_indx_m(void)
+{
+ return 0xff << 24;
+}
+static inline u32 host1x_uclass_wait_syncpt_base_indx_v(u32 r)
+{
+ return (r >> 24) & 0xff;
+}
+static inline u32 host1x_uclass_wait_syncpt_base_base_indx_s(void)
+{
+ return 8;
+}
+static inline u32 host1x_uclass_wait_syncpt_base_base_indx_f(u32 v)
+{
+ return (v & 0xff) << 16;
+}
+static inline u32 host1x_uclass_wait_syncpt_base_base_indx_m(void)
+{
+ return 0xff << 16;
+}
+static inline u32 host1x_uclass_wait_syncpt_base_base_indx_v(u32 r)
+{
+ return (r >> 16) & 0xff;
+}
+static inline u32 host1x_uclass_wait_syncpt_base_offset_s(void)
+{
+ return 16;
+}
+static inline u32 host1x_uclass_wait_syncpt_base_offset_f(u32 v)
+{
+ return (v & 0xffff) << 0;
+}
+static inline u32 host1x_uclass_wait_syncpt_base_offset_m(void)
+{
+ return 0xffff << 0;
+}
+static inline u32 host1x_uclass_wait_syncpt_base_offset_v(u32 r)
+{
+ return (r >> 0) & 0xffff;
+}
+static inline u32 host1x_uclass_load_syncpt_base_r(void)
+{
+ return 0xb;
+}
+static inline u32 host1x_uclass_load_syncpt_base_base_indx_s(void)
+{
+ return 8;
+}
+static inline u32 host1x_uclass_load_syncpt_base_base_indx_f(u32 v)
+{
+ return (v & 0xff) << 24;
+}
+static inline u32 host1x_uclass_load_syncpt_base_base_indx_m(void)
+{
+ return 0xff << 24;
+}
+static inline u32 host1x_uclass_load_syncpt_base_base_indx_v(u32 r)
+{
+ return (r >> 24) & 0xff;
+}
+static inline u32 host1x_uclass_load_syncpt_base_value_s(void)
+{
+ return 24;
+}
+static inline u32 host1x_uclass_load_syncpt_base_value_f(u32 v)
+{
+ return (v & 0xffffff) << 0;
+}
+static inline u32 host1x_uclass_load_syncpt_base_value_m(void)
+{
+ return 0xffffff << 0;
+}
+static inline u32 host1x_uclass_load_syncpt_base_value_v(u32 r)
+{
+ return (r >> 0) & 0xffffff;
+}
+static inline u32 host1x_uclass_incr_syncpt_base_r(void)
+{
+ return 0xc;
+}
+static inline u32 host1x_uclass_incr_syncpt_base_base_indx_s(void)
+{
+ return 8;
+}
+static inline u32 host1x_uclass_incr_syncpt_base_base_indx_f(u32 v)
+{
+ return (v & 0xff) << 24;
+}
+static inline u32 host1x_uclass_incr_syncpt_base_base_indx_m(void)
+{
+ return 0xff << 24;
+}
+static inline u32 host1x_uclass_incr_syncpt_base_base_indx_v(u32 r)
+{
+ return (r >> 24) & 0xff;
+}
+static inline u32 host1x_uclass_incr_syncpt_base_offset_s(void)
+{
+ return 24;
+}
+static inline u32 host1x_uclass_incr_syncpt_base_offset_f(u32 v)
+{
+ return (v & 0xffffff) << 0;
+}
+static inline u32 host1x_uclass_incr_syncpt_base_offset_m(void)
+{
+ return 0xffffff << 0;
+}
+static inline u32 host1x_uclass_incr_syncpt_base_offset_v(u32 r)
+{
+ return (r >> 0) & 0xffffff;
+}
+static inline u32 host1x_uclass_indoff_r(void)
+{
+ return 0x2d;
+}
+static inline u32 host1x_uclass_indoff_indbe_s(void)
+{
+ return 4;
+}
+static inline u32 host1x_uclass_indoff_indbe_f(u32 v)
+{
+ return (v & 0xf) << 28;
+}
+static inline u32 host1x_uclass_indoff_indbe_m(void)
+{
+ return 0xf << 28;
+}
+static inline u32 host1x_uclass_indoff_indbe_v(u32 r)
+{
+ return (r >> 28) & 0xf;
+}
+static inline u32 host1x_uclass_indoff_autoinc_s(void)
+{
+ return 1;
+}
+static inline u32 host1x_uclass_indoff_autoinc_f(u32 v)
+{
+ return (v & 0x1) << 27;
+}
+static inline u32 host1x_uclass_indoff_autoinc_m(void)
+{
+ return 0x1 << 27;
+}
+static inline u32 host1x_uclass_indoff_autoinc_v(u32 r)
+{
+ return (r >> 27) & 0x1;
+}
+static inline u32 host1x_uclass_indoff_spool_s(void)
+{
+ return 1;
+}
+static inline u32 host1x_uclass_indoff_spool_f(u32 v)
+{
+ return (v & 0x1) << 26;
+}
+static inline u32 host1x_uclass_indoff_spool_m(void)
+{
+ return 0x1 << 26;
+}
+static inline u32 host1x_uclass_indoff_spool_v(u32 r)
+{
+ return (r >> 26) & 0x1;
+}
+static inline u32 host1x_uclass_indoff_indoffset_s(void)
+{
+ return 24;
+}
+static inline u32 host1x_uclass_indoff_indoffset_f(u32 v)
+{
+ return (v & 0xffffff) << 2;
+}
+static inline u32 host1x_uclass_indoff_indoffset_m(void)
+{
+ return 0xffffff << 2;
+}
+static inline u32 host1x_uclass_indoff_indoffset_v(u32 r)
+{
+ return (r >> 2) & 0xffffff;
+}
+static inline u32 host1x_uclass_indoff_indmodid_s(void)
+{
+ return 8;
+}
+static inline u32 host1x_uclass_indoff_indmodid_f(u32 v)
+{
+ return (v & 0xff) << 18;
+}
+static inline u32 host1x_uclass_indoff_indmodid_m(void)
+{
+ return 0xff << 18;
+}
+static inline u32 host1x_uclass_indoff_indmodid_v(u32 r)
+{
+ return (r >> 18) & 0xff;
+}
+static inline u32 host1x_uclass_indoff_indmodid_host1x_v(void)
+{
+ return 0;
+}
+static inline u32 host1x_uclass_indoff_indmodid_mpe_v(void)
+{
+ return 1;
+}
+static inline u32 host1x_uclass_indoff_indmodid_vi_v(void)
+{
+ return 2;
+}
+static inline u32 host1x_uclass_indoff_indmodid_epp_v(void)
+{
+ return 3;
+}
+static inline u32 host1x_uclass_indoff_indmodid_isp_v(void)
+{
+ return 4;
+}
+static inline u32 host1x_uclass_indoff_indmodid_gr2d_v(void)
+{
+ return 5;
+}
+static inline u32 host1x_uclass_indoff_indmodid_gr3d_v(void)
+{
+ return 6;
+}
+static inline u32 host1x_uclass_indoff_indmodid_display_v(void)
+{
+ return 8;
+}
+static inline u32 host1x_uclass_indoff_indmodid_tvo_v(void)
+{
+ return 11;
+}
+static inline u32 host1x_uclass_indoff_indmodid_displayb_v(void)
+{
+ return 9;
+}
+static inline u32 host1x_uclass_indoff_indmodid_dsi_v(void)
+{
+ return 12;
+}
+static inline u32 host1x_uclass_indoff_indmodid_hdmi_v(void)
+{
+ return 10;
+}
+static inline u32 host1x_uclass_indoff_indmodid_dsib_v(void)
+{
+ return 16;
+}
+static inline u32 host1x_uclass_indoff_indroffset_s(void)
+{
+ return 16;
+}
+static inline u32 host1x_uclass_indoff_indroffset_f(u32 v)
+{
+ return (v & 0xffff) << 2;
+}
+static inline u32 host1x_uclass_indoff_indroffset_m(void)
+{
+ return 0xffff << 2;
+}
+static inline u32 host1x_uclass_indoff_indroffset_v(u32 r)
+{
+ return (r >> 2) & 0xffff;
+}
+static inline u32 host1x_uclass_indoff_acctype_s(void)
+{
+ return 1;
+}
+static inline u32 host1x_uclass_indoff_acctype_f(u32 v)
+{
+ return (v & 0x1) << 1;
+}
+static inline u32 host1x_uclass_indoff_acctype_m(void)
+{
+ return 0x1 << 1;
+}
+static inline u32 host1x_uclass_indoff_acctype_v(u32 r)
+{
+ return (r >> 1) & 0x1;
+}
+static inline u32 host1x_uclass_indoff_acctype_reg_v(void)
+{
+ return 0;
+}
+static inline u32 host1x_uclass_indoff_acctype_fb_v(void)
+{
+ return 1;
+}
+static inline u32 host1x_uclass_indoff_rwn_s(void)
+{
+ return 1;
+}
+static inline u32 host1x_uclass_indoff_rwn_f(u32 v)
+{
+ return (v & 0x1) << 0;
+}
+static inline u32 host1x_uclass_indoff_rwn_m(void)
+{
+ return 0x1 << 0;
+}
+static inline u32 host1x_uclass_indoff_rwn_v(u32 r)
+{
+ return (r >> 0) & 0x1;
+}
+static inline u32 host1x_uclass_indoff_rwn_write_v(void)
+{
+ return 0;
+}
+static inline u32 host1x_uclass_indoff_rwn_read_v(void)
+{
+ return 1;
+}
+static inline u32 host1x_uclass_inddata_r(void)
+{
+ return 0x2e;
+}
+
+#endif /* __hw_host1x_uclass_host1x_h__ */
diff --git a/drivers/video/tegra/host/isp/isp.c b/drivers/video/tegra/host/isp/isp.c
index 9044d40b8574..0a3cc3b03578 100644
--- a/drivers/video/tegra/host/isp/isp.c
+++ b/drivers/video/tegra/host/isp/isp.c
@@ -18,14 +18,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <linux/resource.h>
-
-#include <mach/iomap.h>
-
#include "dev.h"
#include "bus_client.h"
-static int __devinit isp_probe(struct nvhost_device *dev)
+static int __devinit isp_probe(struct nvhost_device *dev,
+ struct nvhost_device_id *id_table)
{
int err = 0;
@@ -42,6 +39,7 @@ static int __exit isp_remove(struct nvhost_device *dev)
return 0;
}
+#ifdef CONFIG_PM
static int isp_suspend(struct nvhost_device *dev, pm_message_t state)
{
return nvhost_client_device_suspend(dev);
@@ -52,15 +50,7 @@ static int isp_resume(struct nvhost_device *dev)
dev_info(&dev->dev, "resuming\n");
return 0;
}
-
-static struct resource isp_resources = {
- .name = "regs",
- .start = TEGRA_ISP_BASE,
- .end = TEGRA_ISP_BASE + TEGRA_ISP_SIZE - 1,
- .flags = IORESOURCE_MEM,
-};
-
-struct nvhost_device *isp_device;
+#endif
static struct nvhost_driver isp_driver = {
.probe = isp_probe,
@@ -77,18 +67,6 @@ static struct nvhost_driver isp_driver = {
static int __init isp_init(void)
{
- int err;
-
- isp_device = nvhost_get_device("isp");
- if (!isp_device)
- return -ENXIO;
-
- isp_device->resource = &isp_resources;
- isp_device->num_resources = 1;
- err = nvhost_device_register(isp_device);
- if (err)
- return err;
-
return nvhost_driver_register(&isp_driver);
}
diff --git a/drivers/video/tegra/host/mpe/mpe.c b/drivers/video/tegra/host/mpe/mpe.c
index 36d1d6f26682..c738700469c6 100644
--- a/drivers/video/tegra/host/mpe/mpe.c
+++ b/drivers/video/tegra/host/mpe/mpe.c
@@ -19,17 +19,15 @@
*/
#include "nvhost_hwctx.h"
+#include "nvhost_channel.h"
#include "dev.h"
-#include "host1x/host1x_hardware.h"
-#include "host1x/host1x_channel.h"
-#include "host1x/host1x_syncpt.h"
+#include "host1x/host1x01_hardware.h"
#include "host1x/host1x_hwctx.h"
#include "t20/t20.h"
+#include "chip_support.h"
+#include "nvhost_memmgr.h"
#include <linux/slab.h>
-#include <linux/resource.h>
-
-#include <mach/iomap.h>
#include "bus_client.h"
@@ -140,7 +138,7 @@ static void restore_begin(struct host1x_hwctx_handler *h, u32 *ptr)
{
/* set class to host */
ptr[0] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
- NV_CLASS_HOST_INCR_SYNCPT_BASE, 1);
+ host1x_uclass_incr_syncpt_base_r(), 1);
/* increment sync point base */
ptr[1] = nvhost_class_host_incr_syncpt_base(h->waitbase, 1);
/* set class to MPE */
@@ -159,7 +157,8 @@ static void restore_ram(u32 *ptr, unsigned words,
static void restore_end(struct host1x_hwctx_handler *h, u32 *ptr)
{
/* syncpt increment to track restore gather. */
- ptr[0] = nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_OP_DONE,
+ ptr[0] = nvhost_opcode_imm_incr_syncpt(
+ host1x_uclass_incr_syncpt_cond_op_done_v(),
h->syncpt);
}
#define RESTORE_END_SIZE 1
@@ -217,23 +216,26 @@ static void __init save_begin(struct host1x_hwctx_handler *h, u32 *ptr)
{
/* MPE: when done, increment syncpt to base+1 */
ptr[0] = nvhost_opcode_setclass(NV_VIDEO_ENCODE_MPEG_CLASS_ID, 0, 0);
- ptr[1] = nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_OP_DONE, h->syncpt);
+ ptr[1] = nvhost_opcode_imm_incr_syncpt(
+ host1x_uclass_incr_syncpt_cond_op_done_v(), h->syncpt);
/* host: wait for syncpt base+1 */
ptr[2] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
- NV_CLASS_HOST_WAIT_SYNCPT_BASE, 1);
+ host1x_uclass_wait_syncpt_base_r(), 1);
ptr[3] = nvhost_class_host_wait_syncpt_base(h->syncpt, h->waitbase, 1);
/* host: signal context read thread to start reading */
- ptr[4] = nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_IMMEDIATE, h->syncpt);
+ ptr[4] = nvhost_opcode_imm_incr_syncpt(
+ host1x_uclass_incr_syncpt_cond_immediate_v(),
+ h->syncpt);
}
#define SAVE_BEGIN_SIZE 5
static void __init save_direct(u32 *ptr, u32 start_reg, u32 count)
{
ptr[0] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
- NV_CLASS_HOST_INDOFF, 1);
+ host1x_uclass_indoff_r(), 1);
ptr[1] = nvhost_class_host_indoff_reg_read(NV_HOST_MODULE_MPE,
start_reg, true);
- ptr[2] = nvhost_opcode_nonincr(NV_CLASS_HOST_INDDATA, count);
+ ptr[2] = nvhost_opcode_nonincr(host1x_uclass_inddata_r(), count);
}
#define SAVE_DIRECT_SIZE 3
@@ -248,10 +250,10 @@ static void __init save_set_ram_cmd(u32 *ptr, u32 cmd_reg, u32 count)
static void __init save_read_ram_data_nasty(u32 *ptr, u32 data_reg)
{
ptr[0] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
- NV_CLASS_HOST_INDOFF, 1);
+ host1x_uclass_indoff_r(), 1);
ptr[1] = nvhost_class_host_indoff_reg_read(NV_HOST_MODULE_MPE,
data_reg, false);
- ptr[2] = nvhost_opcode_imm(NV_CLASS_HOST_INDDATA, 0);
+ ptr[2] = nvhost_opcode_imm(host1x_uclass_inddata_r(), 0);
/* write junk data to avoid 'cached problem with register memory' */
ptr[3] = nvhost_opcode_setclass(NV_VIDEO_ENCODE_MPEG_CLASS_ID,
data_reg, 1);
@@ -263,10 +265,10 @@ static void __init save_end(struct host1x_hwctx_handler *h, u32 *ptr)
{
/* Wait for context read service to finish (cpu incr 3) */
ptr[0] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
- NV_CLASS_HOST_WAIT_SYNCPT_BASE, 1);
+ host1x_uclass_wait_syncpt_base_r(), 1);
ptr[1] = nvhost_class_host_wait_syncpt_base(h->syncpt, h->waitbase, 3);
/* Advance syncpoint base */
- ptr[2] = nvhost_opcode_nonincr(NV_CLASS_HOST_INCR_SYNCPT_BASE, 1);
+ ptr[2] = nvhost_opcode_nonincr(host1x_uclass_incr_syncpt_base_r(), 1);
ptr[3] = nvhost_class_host_incr_syncpt_base(h->waitbase, 3);
/* set class back to the unit */
ptr[4] = nvhost_opcode_setclass(NV_VIDEO_ENCODE_MPEG_CLASS_ID, 0, 0);
@@ -392,7 +394,7 @@ static u32 *save_regs(u32 *ptr, unsigned int *pending,
u32 count = regs->count;
++ptr; /* restore incr */
if (regs->type == HWCTX_REGINFO_NORMAL) {
- host1x_drain_read_fifo(channel->aperture,
+ nvhost_channel_drain_read_fifo(channel,
ptr, count, pending);
ptr += count;
} else {
@@ -401,8 +403,8 @@ static u32 *save_regs(u32 *ptr, unsigned int *pending,
BUG_ON(msi->out_pos >= NR_WRITEBACKS);
word = msi->out[msi->out_pos++];
} else {
- host1x_drain_read_fifo(channel->aperture,
- &word, 1, pending);
+ nvhost_channel_drain_read_fifo(channel,
+ &word, 1, pending);
if (regs->type == HWCTX_REGINFO_STASH) {
BUG_ON(msi->in_pos >= NR_STASHES);
msi->in[msi->in_pos++] = word;
@@ -422,7 +424,7 @@ static u32 *save_ram(u32 *ptr, unsigned int *pending,
{
int err = 0;
ptr += RESTORE_RAM_SIZE;
- err = host1x_drain_read_fifo(channel->aperture, ptr, words, pending);
+ err = nvhost_channel_drain_read_fifo(channel, ptr, words, pending);
WARN_ON(err);
return ptr + words;
}
@@ -432,23 +434,23 @@ static u32 *save_ram(u32 *ptr, unsigned int *pending,
static struct nvhost_hwctx *ctxmpe_alloc(struct nvhost_hwctx_handler *h,
struct nvhost_channel *ch)
{
- struct nvmap_client *nvmap = nvhost_get_host(ch->dev)->nvmap;
+ struct mem_mgr *memmgr = nvhost_get_host(ch->dev)->memmgr;
struct host1x_hwctx_handler *p = to_host1x_hwctx_handler(h);
struct host1x_hwctx *ctx;
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return NULL;
- ctx->restore = nvmap_alloc(nvmap, restore_size * 4, 32,
- NVMAP_HANDLE_WRITE_COMBINE, 0);
+ ctx->restore = mem_op().alloc(memmgr, restore_size * 4, 32,
+ mem_mgr_flag_write_combine);
if (IS_ERR_OR_NULL(ctx->restore)) {
kfree(ctx);
return NULL;
}
- ctx->restore_virt = nvmap_mmap(ctx->restore);
+ ctx->restore_virt = mem_op().mmap(ctx->restore);
if (!ctx->restore_virt) {
- nvmap_free(nvmap, ctx->restore);
+ mem_op().put(memmgr, ctx->restore);
kfree(ctx);
return NULL;
}
@@ -459,7 +461,8 @@ static struct nvhost_hwctx *ctxmpe_alloc(struct nvhost_hwctx_handler *h,
ctx->hwctx.valid = false;
ctx->save_incrs = 3;
ctx->save_thresh = 2;
- ctx->restore_phys = nvmap_pin(nvmap, ctx->restore);
+ ctx->save_slots = p->save_slots;
+ ctx->restore_phys = mem_op().pin(memmgr, ctx->restore);
ctx->restore_size = restore_size;
ctx->restore_incrs = 1;
@@ -477,13 +480,12 @@ static void ctxmpe_free(struct kref *ref)
{
struct nvhost_hwctx *nctx = container_of(ref, struct nvhost_hwctx, ref);
struct host1x_hwctx *ctx = to_host1x_hwctx(nctx);
- struct nvmap_client *nvmap =
- nvhost_get_host(nctx->channel->dev)->nvmap;
+ struct mem_mgr *memmgr = nvhost_get_host(nctx->channel->dev)->memmgr;
if (ctx->restore_virt)
- nvmap_munmap(ctx->restore, ctx->restore_virt);
- nvmap_unpin(nvmap, ctx->restore);
- nvmap_free(nvmap, ctx->restore);
+ mem_op().munmap(ctx->restore, ctx->restore_virt);
+ mem_op().unpin(memmgr, ctx->restore);
+ mem_op().put(memmgr, ctx->restore);
kfree(ctx);
}
@@ -497,7 +499,10 @@ static void ctxmpe_save_push(struct nvhost_hwctx *nctx,
{
struct host1x_hwctx *ctx = to_host1x_hwctx(nctx);
struct host1x_hwctx_handler *h = host1x_hwctx_handler(ctx);
- nvhost_cdma_push(cdma,
+ nvhost_cdma_push_gather(cdma,
+ nvhost_get_host(nctx->channel->dev)->memmgr,
+ h->save_buf,
+ 0,
nvhost_opcode_gather(h->save_size),
h->save_phys);
}
@@ -528,11 +533,10 @@ static void ctxmpe_save_service(struct nvhost_hwctx *nctx)
h->syncpt);
}
-struct nvhost_hwctx_handler *nvhost_mpe_ctxhandler_init(
- u32 syncpt, u32 waitbase,
- struct nvhost_channel *ch)
+struct nvhost_hwctx_handler *nvhost_mpe_ctxhandler_init(u32 syncpt,
+ u32 waitbase, struct nvhost_channel *ch)
{
- struct nvmap_client *nvmap;
+ struct mem_mgr *memmgr;
u32 *save_ptr;
struct host1x_hwctx_handler *p;
@@ -540,28 +544,29 @@ struct nvhost_hwctx_handler *nvhost_mpe_ctxhandler_init(
if (!p)
return NULL;
- nvmap = nvhost_get_host(ch->dev)->nvmap;
+ memmgr = nvhost_get_host(ch->dev)->memmgr;
p->syncpt = syncpt;
p->waitbase = waitbase;
setup_save(p, NULL);
- p->save_buf = nvmap_alloc(nvmap, p->save_size * 4, 32,
- NVMAP_HANDLE_WRITE_COMBINE, 0);
+ p->save_buf = mem_op().alloc(memmgr, p->save_size * 4, 32,
+ mem_mgr_flag_write_combine);
if (IS_ERR(p->save_buf)) {
p->save_buf = NULL;
return NULL;
}
- save_ptr = nvmap_mmap(p->save_buf);
+ save_ptr = mem_op().mmap(p->save_buf);
if (!save_ptr) {
- nvmap_free(nvmap, p->save_buf);
+ mem_op().put(memmgr, p->save_buf);
p->save_buf = NULL;
return NULL;
}
- p->save_phys = nvmap_pin(nvmap, p->save_buf);
+ p->save_phys = mem_op().pin(memmgr, p->save_buf);
+ p->save_slots = 1;
setup_save(p, save_ptr);
@@ -576,12 +581,50 @@ struct nvhost_hwctx_handler *nvhost_mpe_ctxhandler_init(
int nvhost_mpe_prepare_power_off(struct nvhost_device *dev)
{
- return host1x_save_context(dev, NVSYNCPT_MPE);
+ return nvhost_channel_save_context(dev->channel);
}
-static int __devinit mpe_probe(struct nvhost_device *dev)
+enum mpe_ip_ver {
+ mpe_01 = 1,
+ mpe_02,
+};
+
+struct mpe_desc {
+ int (*prepare_poweroff)(struct nvhost_device *dev);
+ struct nvhost_hwctx_handler *(*alloc_hwctx_handler)(u32 syncpt,
+ u32 waitbase, struct nvhost_channel *ch);
+};
+
+static const struct mpe_desc mpe[] = {
+ [mpe_01] = {
+ .prepare_poweroff = nvhost_mpe_prepare_power_off,
+ .alloc_hwctx_handler = nvhost_mpe_ctxhandler_init,
+ },
+ [mpe_02] = {
+ .prepare_poweroff = nvhost_mpe_prepare_power_off,
+ .alloc_hwctx_handler = nvhost_mpe_ctxhandler_init,
+ },
+};
+
+static struct nvhost_device_id mpe_id[] = {
+ { "mpe", mpe_01 },
+ { "mpe", mpe_02 },
+ { },
+};
+
+MODULE_DEVICE_TABLE(nvhost, mpe_id);
+
+static int __devinit mpe_probe(struct nvhost_device *dev,
+ struct nvhost_device_id *id_table)
{
int err = 0;
+ int index = 0;
+ struct nvhost_driver *drv = to_nvhost_driver(dev->dev.driver);
+
+ index = id_table->version;
+
+ drv->prepare_poweroff = mpe[index].prepare_poweroff;
+ drv->alloc_hwctx_handler = mpe[index].alloc_hwctx_handler;
err = nvhost_client_device_get_resources(dev);
if (err)
@@ -596,6 +639,7 @@ static int __exit mpe_remove(struct nvhost_device *dev)
return 0;
}
+#ifdef CONFIG_PM
static int mpe_suspend(struct nvhost_device *dev, pm_message_t state)
{
return nvhost_client_device_suspend(dev);
@@ -606,15 +650,7 @@ static int mpe_resume(struct nvhost_device *dev)
dev_info(&dev->dev, "resuming\n");
return 0;
}
-
-static struct resource mpe_resources = {
- .name = "regs",
- .start = TEGRA_MPE_BASE,
- .end = TEGRA_MPE_BASE + TEGRA_MPE_SIZE - 1,
- .flags = IORESOURCE_MEM,
-};
-
-struct nvhost_device *mpe_device;
+#endif
static struct nvhost_driver mpe_driver = {
.probe = mpe_probe,
@@ -626,24 +662,12 @@ static struct nvhost_driver mpe_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "mpe",
- }
+ },
+ .id_table = mpe_id,
};
static int __init mpe_init(void)
{
- int err;
-
- mpe_device = nvhost_get_device("mpe");
- if (!mpe_device)
- return -ENXIO;
-
- /* use ARRAY_SIZE macro if resources are more than 1 */
- mpe_device->resource = &mpe_resources;
- mpe_device->num_resources = 1;
- err = nvhost_device_register(mpe_device);
- if (err)
- return err;
-
return nvhost_driver_register(&mpe_driver);
}
diff --git a/drivers/video/tegra/host/nvhost_acm.c b/drivers/video/tegra/host/nvhost_acm.c
index 015b7c4dbf66..06005c423a21 100644
--- a/drivers/video/tegra/host/nvhost_acm.c
+++ b/drivers/video/tegra/host/nvhost_acm.c
@@ -3,7 +3,7 @@
*
* Tegra Graphics Host Automatic Clock Management
*
- * Copyright (c) 2010-2012, NVIDIA Corporation.
+ * Copyright (c) 2010-2012, NVIDIA Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -31,9 +31,9 @@
#include <mach/clk.h>
#include <mach/hardware.h>
-#define ACM_SUSPEND_WAIT_FOR_IDLE_TIMEOUT (2 * HZ)
-#define POWERGATE_DELAY 10
-#define MAX_DEVID_LENGTH 16
+#define ACM_SUSPEND_WAIT_FOR_IDLE_TIMEOUT (2 * HZ)
+#define POWERGATE_DELAY 10
+#define MAX_DEVID_LENGTH 16
DEFINE_MUTEX(client_list_lock);
@@ -120,9 +120,12 @@ static void to_state_clockgated_locked(struct nvhost_device *dev)
static void to_state_running_locked(struct nvhost_device *dev)
{
+ struct nvhost_driver *drv = to_nvhost_driver(dev->dev.driver);
int prev_state = dev->powerstate;
+
if (dev->powerstate == NVHOST_POWER_STATE_POWERGATED)
to_state_clockgated_locked(dev);
+
if (dev->powerstate == NVHOST_POWER_STATE_CLOCKGATED) {
int i;
@@ -131,12 +134,16 @@ static void to_state_running_locked(struct nvhost_device *dev)
for (i = 0; i < dev->num_clks; i++) {
int err = clk_enable(dev->clk[i]);
- BUG_ON(err);
+ if (err) {
+ dev_err(&dev->dev, "Cannot turn on clock %s",
+ dev->clocks[i].name);
+ return;
+ }
}
if (prev_state == NVHOST_POWER_STATE_POWERGATED
- && dev->finalize_poweron)
- dev->finalize_poweron(dev);
+ && drv->finalize_poweron)
+ drv->finalize_poweron(dev);
}
dev->powerstate = NVHOST_POWER_STATE_RUNNING;
}
@@ -148,12 +155,13 @@ static void to_state_running_locked(struct nvhost_device *dev)
static int to_state_powergated_locked(struct nvhost_device *dev)
{
int err = 0;
+ struct nvhost_driver *drv = to_nvhost_driver(dev->dev.driver);
- if (dev->prepare_poweroff
+ if (drv->prepare_poweroff
&& dev->powerstate != NVHOST_POWER_STATE_POWERGATED) {
/* Clock needs to be on in prepare_poweroff */
to_state_running_locked(dev);
- err = dev->prepare_poweroff(dev);
+ err = drv->prepare_poweroff(dev);
if (err)
return err;
}
@@ -185,8 +193,10 @@ static void schedule_clockgating_locked(struct nvhost_device *dev)
void nvhost_module_busy(struct nvhost_device *dev)
{
- if (dev->busy)
- dev->busy(dev);
+ struct nvhost_driver *drv = to_nvhost_driver(dev->dev.driver);
+
+ if (drv->busy)
+ drv->busy(dev);
mutex_lock(&dev->lock);
cancel_delayed_work(&dev->powerstate_down);
@@ -223,9 +233,9 @@ static void powerstate_down_handler(struct work_struct *work)
mutex_unlock(&dev->lock);
}
-
void nvhost_module_idle_mult(struct nvhost_device *dev, int refs)
{
+ struct nvhost_driver *drv = to_nvhost_driver(dev->dev.driver);
bool kick = false;
mutex_lock(&dev->lock);
@@ -240,8 +250,8 @@ void nvhost_module_idle_mult(struct nvhost_device *dev, int refs)
if (kick) {
wake_up(&dev->idle_wq);
- if (dev->idle)
- dev->idle(dev);
+ if (drv->idle)
+ drv->idle(dev);
}
}
@@ -349,9 +359,103 @@ void nvhost_module_remove_client(struct nvhost_device *dev, void *priv)
mutex_unlock(&client_list_lock);
}
+static ssize_t refcount_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ int ret;
+ struct nvhost_device_power_attr *power_attribute =
+ container_of(attr, struct nvhost_device_power_attr, \
+ power_attr[NVHOST_POWER_SYSFS_ATTRIB_REFCOUNT]);
+ struct nvhost_device *dev = power_attribute->ndev;
+
+ mutex_lock(&dev->lock);
+ ret = sprintf(buf, "%d\n", dev->refcount);
+ mutex_unlock(&dev->lock);
+
+ return ret;
+}
+
+static ssize_t powergate_delay_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ int powergate_delay = 0, ret = 0;
+ struct nvhost_device_power_attr *power_attribute =
+ container_of(attr, struct nvhost_device_power_attr, \
+ power_attr[NVHOST_POWER_SYSFS_ATTRIB_POWERGATE_DELAY]);
+ struct nvhost_device *dev = power_attribute->ndev;
+
+ if (!dev->can_powergate) {
+ dev_info(&dev->dev, "does not support power-gating\n");
+ return count;
+ }
+
+ mutex_lock(&dev->lock);
+ ret = sscanf(buf, "%d", &powergate_delay);
+ if (ret == 1 && powergate_delay >= 0)
+ dev->powergate_delay = powergate_delay;
+ else
+ dev_err(&dev->dev, "Invalid powergate delay\n");
+ mutex_unlock(&dev->lock);
+
+ return count;
+}
+
+static ssize_t powergate_delay_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ int ret;
+ struct nvhost_device_power_attr *power_attribute =
+ container_of(attr, struct nvhost_device_power_attr, \
+ power_attr[NVHOST_POWER_SYSFS_ATTRIB_POWERGATE_DELAY]);
+ struct nvhost_device *dev = power_attribute->ndev;
+
+ mutex_lock(&dev->lock);
+ ret = sprintf(buf, "%d\n", dev->powergate_delay);
+ mutex_unlock(&dev->lock);
+
+ return ret;
+}
+
+static ssize_t clockgate_delay_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ int clockgate_delay = 0, ret = 0;
+ struct nvhost_device_power_attr *power_attribute =
+ container_of(attr, struct nvhost_device_power_attr, \
+ power_attr[NVHOST_POWER_SYSFS_ATTRIB_CLOCKGATE_DELAY]);
+ struct nvhost_device *dev = power_attribute->ndev;
+
+ mutex_lock(&dev->lock);
+ ret = sscanf(buf, "%d", &clockgate_delay);
+ if (ret == 1 && clockgate_delay >= 0)
+ dev->clockgate_delay = clockgate_delay;
+ else
+ dev_err(&dev->dev, "Invalid clockgate delay\n");
+ mutex_unlock(&dev->lock);
+
+ return count;
+}
+
+static ssize_t clockgate_delay_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ int ret;
+ struct nvhost_device_power_attr *power_attribute =
+ container_of(attr, struct nvhost_device_power_attr, \
+ power_attr[NVHOST_POWER_SYSFS_ATTRIB_CLOCKGATE_DELAY]);
+ struct nvhost_device *dev = power_attribute->ndev;
+
+ mutex_lock(&dev->lock);
+ ret = sprintf(buf, "%d\n", dev->clockgate_delay);
+ mutex_unlock(&dev->lock);
+
+ return ret;
+}
+
int nvhost_module_init(struct nvhost_device *dev)
{
- int i = 0;
+ int i = 0, err = 0;
+ struct kobj_attribute *attr = NULL;
/* initialize clocks to known state */
INIT_LIST_HEAD(&dev->client_list);
@@ -362,7 +466,11 @@ int nvhost_module_init(struct nvhost_device *dev)
snprintf(devname, MAX_DEVID_LENGTH, "tegra_%s", dev->name);
c = clk_get_sys(devname, dev->clocks[i].name);
- BUG_ON(IS_ERR_OR_NULL(c));
+ if (IS_ERR_OR_NULL(c)) {
+ dev_err(&dev->dev, "Cannot get clock %s\n",
+ dev->clocks[i].name);
+ continue;
+ }
rate = clk_round_rate(c, rate);
clk_enable(c);
@@ -388,7 +496,71 @@ int nvhost_module_init(struct nvhost_device *dev)
dev->powerstate = NVHOST_POWER_STATE_CLOCKGATED;
}
+ /* Init the power sysfs attributes for this device */
+ dev->power_attrib = kzalloc(sizeof(struct nvhost_device_power_attr),
+ GFP_KERNEL);
+ if (!dev->power_attrib) {
+ dev_err(&dev->dev, "Unable to allocate sysfs attributes\n");
+ return -ENOMEM;
+ }
+ dev->power_attrib->ndev = dev;
+
+ dev->power_kobj = kobject_create_and_add("acm", &dev->dev.kobj);
+ if (!dev->power_kobj) {
+ dev_err(&dev->dev, "Could not add dir 'power'\n");
+ err = -EIO;
+ goto fail_attrib_alloc;
+ }
+
+ attr = &dev->power_attrib->power_attr[NVHOST_POWER_SYSFS_ATTRIB_CLOCKGATE_DELAY];
+ attr->attr.name = "clockgate_delay";
+ attr->attr.mode = S_IWUSR | S_IRUGO;
+ attr->show = clockgate_delay_show;
+ attr->store = clockgate_delay_store;
+ if (sysfs_create_file(dev->power_kobj, &attr->attr)) {
+ dev_err(&dev->dev, "Could not create sysfs attribute clockgate_delay\n");
+ err = -EIO;
+ goto fail_clockdelay;
+ }
+
+ attr = &dev->power_attrib->power_attr[NVHOST_POWER_SYSFS_ATTRIB_POWERGATE_DELAY];
+ attr->attr.name = "powergate_delay";
+ attr->attr.mode = S_IWUSR | S_IRUGO;
+ attr->show = powergate_delay_show;
+ attr->store = powergate_delay_store;
+ if (sysfs_create_file(dev->power_kobj, &attr->attr)) {
+ dev_err(&dev->dev, "Could not create sysfs attribute powergate_delay\n");
+ err = -EIO;
+ goto fail_powergatedelay;
+ }
+
+ attr = &dev->power_attrib->power_attr[NVHOST_POWER_SYSFS_ATTRIB_REFCOUNT];
+ attr->attr.name = "refcount";
+ attr->attr.mode = S_IRUGO;
+ attr->show = refcount_show;
+ if (sysfs_create_file(dev->power_kobj, &attr->attr)) {
+ dev_err(&dev->dev, "Could not create sysfs attribute refcount\n");
+ err = -EIO;
+ goto fail_refcount;
+ }
+
return 0;
+
+fail_refcount:
+ attr = &dev->power_attrib->power_attr[NVHOST_POWER_SYSFS_ATTRIB_POWERGATE_DELAY];
+ sysfs_remove_file(dev->power_kobj, &attr->attr);
+
+fail_powergatedelay:
+ attr = &dev->power_attrib->power_attr[NVHOST_POWER_SYSFS_ATTRIB_CLOCKGATE_DELAY];
+ sysfs_remove_file(dev->power_kobj, &attr->attr);
+
+fail_clockdelay:
+ kobject_put(dev->power_kobj);
+
+fail_attrib_alloc:
+ kfree(dev->power_attrib);
+
+ return err;
}
static int is_module_idle(struct nvhost_device *dev)
@@ -403,6 +575,7 @@ static int is_module_idle(struct nvhost_device *dev)
int nvhost_module_suspend(struct nvhost_device *dev)
{
int ret;
+ struct nvhost_driver *drv = to_nvhost_driver(dev->dev.driver);
ret = wait_event_timeout(dev->idle_wq, is_module_idle(dev),
ACM_SUSPEND_WAIT_FOR_IDLE_TIMEOUT);
@@ -417,8 +590,8 @@ int nvhost_module_suspend(struct nvhost_device *dev)
to_state_powergated_locked(dev);
mutex_unlock(&dev->lock);
- if (dev->suspend)
- dev->suspend(dev);
+ if (drv->suspend_ndev)
+ drv->suspend_ndev(dev);
return 0;
}
@@ -426,9 +599,10 @@ int nvhost_module_suspend(struct nvhost_device *dev)
void nvhost_module_deinit(struct nvhost_device *dev)
{
int i;
+ struct nvhost_driver *drv = to_nvhost_driver(dev->dev.driver);
- if (dev->deinit)
- dev->deinit(dev);
+ if (drv->deinit)
+ drv->deinit(dev);
nvhost_module_suspend(dev);
for (i = 0; i < dev->num_clks; i++)
@@ -436,3 +610,18 @@ void nvhost_module_deinit(struct nvhost_device *dev)
dev->powerstate = NVHOST_POWER_STATE_DEINIT;
}
+/* public host1x power management APIs */
+bool nvhost_module_powered_ext(struct nvhost_device *dev)
+{
+ return nvhost_module_powered(dev);
+}
+
+void nvhost_module_busy_ext(struct nvhost_device *dev)
+{
+ nvhost_module_busy(dev);
+}
+
+void nvhost_module_idle_ext(struct nvhost_device *dev)
+{
+ nvhost_module_idle(dev);
+}
diff --git a/drivers/video/tegra/host/nvhost_acm.h b/drivers/video/tegra/host/nvhost_acm.h
index d2562e9a369f..a5894dcfc0b2 100644
--- a/drivers/video/tegra/host/nvhost_acm.h
+++ b/drivers/video/tegra/host/nvhost_acm.h
@@ -45,7 +45,6 @@ int nvhost_module_get_rate(struct nvhost_device *dev,
int nvhost_module_set_rate(struct nvhost_device *dev, void *priv,
unsigned long rate, int index);
-
static inline bool nvhost_module_powered(struct nvhost_device *dev)
{
return dev->powerstate == NVHOST_POWER_STATE_RUNNING;
@@ -56,5 +55,4 @@ static inline void nvhost_module_idle(struct nvhost_device *dev)
nvhost_module_idle_mult(dev, 1);
}
-
#endif
diff --git a/drivers/video/tegra/host/nvhost_cdma.c b/drivers/video/tegra/host/nvhost_cdma.c
index 775d761e65c9..dae3b7e6182d 100644
--- a/drivers/video/tegra/host/nvhost_cdma.c
+++ b/drivers/video/tegra/host/nvhost_cdma.c
@@ -19,7 +19,13 @@
*/
#include "nvhost_cdma.h"
+#include "nvhost_channel.h"
+#include "nvhost_job.h"
+#include "nvhost_hwctx.h"
#include "dev.h"
+#include "debug.h"
+#include "nvhost_memmgr.h"
+#include "chip_support.h"
#include <asm/cacheflush.h>
#include <linux/slab.h>
@@ -49,6 +55,18 @@ static void add_to_sync_queue(struct nvhost_cdma *cdma,
job->num_slots = nr_slots;
nvhost_job_get(job);
list_add_tail(&job->list, &cdma->sync_queue);
+
+ switch (job->priority) {
+ case NVHOST_PRIORITY_HIGH:
+ cdma->high_prio_count++;
+ break;
+ case NVHOST_PRIORITY_MEDIUM:
+ cdma->med_prio_count++;
+ break;
+ case NVHOST_PRIORITY_LOW:
+ cdma->low_prio_count++;
+ break;
+ }
}
/**
@@ -65,8 +83,8 @@ static unsigned int cdma_status_locked(struct nvhost_cdma *cdma,
return list_empty(&cdma->sync_queue) ? 1 : 0;
case CDMA_EVENT_PUSH_BUFFER_SPACE: {
struct push_buffer *pb = &cdma->push_buffer;
- BUG_ON(!cdma_pb_op(cdma).space);
- return cdma_pb_op(cdma).space(pb);
+ BUG_ON(!cdma_pb_op().space);
+ return cdma_pb_op().space(pb);
}
default:
return 0;
@@ -92,7 +110,13 @@ unsigned int nvhost_cdma_wait_locked(struct nvhost_cdma *cdma,
trace_nvhost_wait_cdma(cdma_to_channel(cdma)->dev->name,
event);
- BUG_ON(cdma->event != CDMA_EVENT_NONE);
+ /* If somebody has managed to already start waiting, yield */
+ if (cdma->event != CDMA_EVENT_NONE) {
+ mutex_unlock(&cdma->lock);
+ schedule();
+ mutex_lock(&cdma->lock);
+ continue;
+ }
cdma->event = event;
mutex_unlock(&cdma->lock);
@@ -153,7 +177,9 @@ static void update_cdma_locked(struct nvhost_cdma *cdma)
struct nvhost_syncpt *sp = &dev->syncpt;
struct nvhost_job *job, *n;
- BUG_ON(!cdma->running);
+ /* If CDMA is stopped, queue is cleared and we can return */
+ if (!cdma->running)
+ return;
/*
* Walk the sync queue, reading the sync point registers as necessary,
@@ -181,13 +207,26 @@ static void update_cdma_locked(struct nvhost_cdma *cdma)
/* Pop push buffer slots */
if (job->num_slots) {
struct push_buffer *pb = &cdma->push_buffer;
- BUG_ON(!cdma_pb_op(cdma).pop_from);
- cdma_pb_op(cdma).pop_from(pb, job->num_slots);
+ BUG_ON(!cdma_pb_op().pop_from);
+ cdma_pb_op().pop_from(pb, job->num_slots);
if (cdma->event == CDMA_EVENT_PUSH_BUFFER_SPACE)
signal = true;
}
list_del(&job->list);
+
+ switch (job->priority) {
+ case NVHOST_PRIORITY_HIGH:
+ cdma->high_prio_count--;
+ break;
+ case NVHOST_PRIORITY_MEDIUM:
+ cdma->med_prio_count--;
+ break;
+ case NVHOST_PRIORITY_LOW:
+ cdma->low_prio_count--;
+ break;
+ }
+
nvhost_job_put(job);
}
@@ -203,17 +242,16 @@ static void update_cdma_locked(struct nvhost_cdma *cdma)
}
void nvhost_cdma_update_sync_queue(struct nvhost_cdma *cdma,
- struct nvhost_syncpt *syncpt, struct device *dev)
+ struct nvhost_syncpt *syncpt, struct nvhost_device *dev)
{
u32 get_restart;
u32 syncpt_incrs;
- bool exec_ctxsave;
struct nvhost_job *job = NULL;
u32 syncpt_val;
syncpt_val = nvhost_syncpt_update_min(syncpt, cdma->timeout.syncpt_id);
- dev_dbg(dev,
+ dev_dbg(&dev->dev,
"%s: starting cleanup (thresh %d)\n",
__func__, syncpt_val);
@@ -224,7 +262,7 @@ void nvhost_cdma_update_sync_queue(struct nvhost_cdma *cdma,
* where a syncpt incr happens just prior/during the teardown.
*/
- dev_dbg(dev,
+ dev_dbg(&dev->dev,
"%s: skip completed buffers still in sync_queue\n",
__func__);
@@ -232,7 +270,7 @@ void nvhost_cdma_update_sync_queue(struct nvhost_cdma *cdma,
if (syncpt_val < job->syncpt_end)
break;
- nvhost_job_dump(dev, job);
+ nvhost_job_dump(&dev->dev, job);
}
/*
@@ -250,7 +288,7 @@ void nvhost_cdma_update_sync_queue(struct nvhost_cdma *cdma,
* properly for this buffer and resources are freed.
*/
- dev_dbg(dev,
+ dev_dbg(&dev->dev,
"%s: perform CPU incr on pending same ctx buffers\n",
__func__);
@@ -268,61 +306,27 @@ void nvhost_cdma_update_sync_queue(struct nvhost_cdma *cdma,
job->timeout = 0;
syncpt_incrs = job->syncpt_end - syncpt_val;
- dev_dbg(dev,
+ dev_dbg(&dev->dev,
"%s: CPU incr (%d)\n", __func__, syncpt_incrs);
- nvhost_job_dump(dev, job);
+ nvhost_job_dump(&dev->dev, job);
/* safe to use CPU to incr syncpts */
- cdma_op(cdma).timeout_cpu_incr(cdma,
+ cdma_op().timeout_cpu_incr(cdma,
job->first_get,
syncpt_incrs,
job->syncpt_end,
- job->num_slots);
+ job->num_slots,
+ dev->waitbases);
syncpt_val += syncpt_incrs;
}
- dev_dbg(dev,
- "%s: GPU incr blocked interleaved ctx buffers\n",
- __func__);
-
- exec_ctxsave = false;
-
- /* setup GPU increments */
- list_for_each_entry_from(job, &cdma->sync_queue, list) {
- /* same context, increment in the pushbuffer */
- if (job->clientid == cdma->timeout.clientid) {
- /* won't need a timeout when replayed */
- job->timeout = 0;
-
- /* update buffer's syncpts in the pushbuffer */
- cdma_op(cdma).timeout_pb_incr(cdma,
- job->first_get,
- job->syncpt_incrs,
- job->num_slots,
- exec_ctxsave);
-
- exec_ctxsave = false;
- } else {
- dev_dbg(dev,
- "%s: switch to a different userctx\n",
- __func__);
- /*
- * If previous context was the timed out context
- * then clear its CTXSAVE in this slot.
- */
- exec_ctxsave = true;
- }
-
- nvhost_job_dump(dev, job);
- }
-
- dev_dbg(dev,
+ dev_dbg(&dev->dev,
"%s: finished sync_queue modification\n", __func__);
/* roll back DMAGET and start up channel again */
- cdma_op(cdma).timeout_teardown_end(cdma, get_restart);
+ cdma_op().timeout_teardown_end(cdma, get_restart);
if (cdma->timeout.ctx)
cdma->timeout.ctx->has_timedout = true;
@@ -335,7 +339,7 @@ int nvhost_cdma_init(struct nvhost_cdma *cdma)
{
int err;
struct push_buffer *pb = &cdma->push_buffer;
- BUG_ON(!cdma_pb_op(cdma).init);
+ BUG_ON(!cdma_pb_op().init);
mutex_init(&cdma->lock);
sema_init(&cdma->sem, 0);
@@ -345,7 +349,7 @@ int nvhost_cdma_init(struct nvhost_cdma *cdma)
cdma->running = false;
cdma->torndown = false;
- err = cdma_pb_op(cdma).init(pb);
+ err = cdma_pb_op().init(pb);
if (err)
return err;
return 0;
@@ -358,10 +362,10 @@ void nvhost_cdma_deinit(struct nvhost_cdma *cdma)
{
struct push_buffer *pb = &cdma->push_buffer;
- BUG_ON(!cdma_pb_op(cdma).destroy);
+ BUG_ON(!cdma_pb_op().destroy);
BUG_ON(cdma->running);
- cdma_pb_op(cdma).destroy(pb);
- cdma_op(cdma).timeout_destroy(cdma);
+ cdma_pb_op().destroy(pb);
+ cdma_op().timeout_destroy(cdma);
}
/**
@@ -375,8 +379,8 @@ int nvhost_cdma_begin(struct nvhost_cdma *cdma, struct nvhost_job *job)
/* init state on first submit with timeout value */
if (!cdma->timeout.initialized) {
int err;
- BUG_ON(!cdma_op(cdma).timeout_init);
- err = cdma_op(cdma).timeout_init(cdma,
+ BUG_ON(!cdma_op().timeout_init);
+ err = cdma_op().timeout_init(cdma,
job->syncpt_id);
if (err) {
mutex_unlock(&cdma->lock);
@@ -385,22 +389,56 @@ int nvhost_cdma_begin(struct nvhost_cdma *cdma, struct nvhost_job *job)
}
}
if (!cdma->running) {
- BUG_ON(!cdma_op(cdma).start);
- cdma_op(cdma).start(cdma);
+ BUG_ON(!cdma_op().start);
+ cdma_op().start(cdma);
}
cdma->slots_free = 0;
cdma->slots_used = 0;
- cdma->first_get = cdma_pb_op(cdma).putptr(&cdma->push_buffer);
+ cdma->first_get = cdma_pb_op().putptr(&cdma->push_buffer);
return 0;
}
+static void trace_write_gather(struct nvhost_cdma *cdma,
+ struct mem_handle *ref,
+ u32 offset, u32 words)
+{
+ void *mem = NULL;
+
+ if (nvhost_debug_trace_cmdbuf) {
+ mem = mem_op().mmap(ref);
+ if (IS_ERR_OR_NULL(mem))
+ mem = NULL;
+ };
+
+ if (mem) {
+ u32 i;
+ /*
+ * Write in batches of 128 as there seems to be a limit
+ * of how much you can output to ftrace at once.
+ */
+ for (i = 0; i < words; i += TRACE_MAX_LENGTH) {
+ trace_nvhost_cdma_push_gather(
+ cdma_to_channel(cdma)->dev->name,
+ (u32)ref,
+ min(words - i, TRACE_MAX_LENGTH),
+ offset + i * sizeof(u32),
+ mem);
+ }
+ mem_op().munmap(ref, mem);
+ }
+}
+
/**
* Push two words into a push buffer slot
* Blocks as necessary if the push buffer is full.
*/
void nvhost_cdma_push(struct nvhost_cdma *cdma, u32 op1, u32 op2)
{
- nvhost_cdma_push_gather(cdma, NULL, NULL, op1, op2);
+ if (nvhost_debug_trace_cmdbuf)
+ trace_nvhost_cdma_push(cdma_to_channel(cdma)->dev->name,
+ op1, op2);
+
+ nvhost_cdma_push_gather(cdma, NULL, NULL, 0, op1, op2);
}
/**
@@ -408,21 +446,26 @@ void nvhost_cdma_push(struct nvhost_cdma *cdma, u32 op1, u32 op2)
* Blocks as necessary if the push buffer is full.
*/
void nvhost_cdma_push_gather(struct nvhost_cdma *cdma,
- struct nvmap_client *client,
- struct nvmap_handle *handle, u32 op1, u32 op2)
+ struct mem_mgr *client, struct mem_handle *handle,
+ u32 offset, u32 op1, u32 op2)
{
u32 slots_free = cdma->slots_free;
struct push_buffer *pb = &cdma->push_buffer;
- BUG_ON(!cdma_pb_op(cdma).push_to);
- BUG_ON(!cdma_op(cdma).kick);
+
+ BUG_ON(!cdma_pb_op().push_to);
+ BUG_ON(!cdma_op().kick);
+
+ if (handle)
+ trace_write_gather(cdma, handle, offset, op1 & 0xffff);
+
if (slots_free == 0) {
- cdma_op(cdma).kick(cdma);
+ cdma_op().kick(cdma);
slots_free = nvhost_cdma_wait_locked(cdma,
CDMA_EVENT_PUSH_BUFFER_SPACE);
}
cdma->slots_free = slots_free - 1;
cdma->slots_used++;
- cdma_pb_op(cdma).push_to(pb, client, handle, op1, op2);
+ cdma_pb_op().push_to(pb, client, handle, op1, op2);
}
/**
@@ -436,8 +479,8 @@ void nvhost_cdma_end(struct nvhost_cdma *cdma,
{
bool was_idle = list_empty(&cdma->sync_queue);
- BUG_ON(!cdma_op(cdma).kick);
- cdma_op(cdma).kick(cdma);
+ BUG_ON(!cdma_op().kick);
+ cdma_op().kick(cdma);
BUG_ON(job->syncpt_id == NVSYNCPT_INVALID);
@@ -450,6 +493,12 @@ void nvhost_cdma_end(struct nvhost_cdma *cdma,
if (job->timeout && was_idle)
cdma_start_timer_locked(cdma, job);
+ trace_nvhost_cdma_end(job->ch->dev->name,
+ job->priority,
+ job->ch->cdma.high_prio_count,
+ job->ch->cdma.med_prio_count,
+ job->ch->cdma.low_prio_count);
+
mutex_unlock(&cdma->lock);
}
@@ -474,6 +523,8 @@ int nvhost_cdma_flush(struct nvhost_cdma *cdma, int timeout)
unsigned int space, err = 0;
unsigned long end_jiffies = jiffies + msecs_to_jiffies(timeout);
+ trace_nvhost_cdma_flush(cdma_to_channel(cdma)->dev->name, timeout);
+
/*
* Wait for at most timeout ms. Recalculate timeout at each iteration
* to better keep within given timeout.
diff --git a/drivers/video/tegra/host/nvhost_cdma.h b/drivers/video/tegra/host/nvhost_cdma.h
index 9cb9b8277254..a9522c5f6326 100644
--- a/drivers/video/tegra/host/nvhost_cdma.h
+++ b/drivers/video/tegra/host/nvhost_cdma.h
@@ -25,14 +25,13 @@
#include <linux/semaphore.h>
#include <linux/nvhost.h>
-#include <mach/nvmap.h>
#include <linux/list.h>
-#include "nvhost_acm.h"
-
struct nvhost_syncpt;
struct nvhost_userctx_timeout;
struct nvhost_job;
+struct mem_mgr;
+struct mem_handle;
/*
* cdma
@@ -48,27 +47,13 @@ struct nvhost_job;
* update - call to update sync queue and push buffer, unpin memory
*/
-struct nvmap_client_handle {
- struct nvmap_client *client;
- struct nvmap_handle *handle;
-};
-
struct push_buffer {
- struct nvmap_handle_ref *mem; /* handle to pushbuffer memory */
+ struct mem_handle *mem; /* handle to pushbuffer memory */
u32 *mapped; /* mapped pushbuffer memory */
u32 phys; /* physical address of pushbuffer */
u32 fence; /* index we've written */
u32 cur; /* index to write to */
- struct nvmap_client_handle *nvmap;
- /* nvmap handle for each opcode pair */
-};
-
-struct syncpt_buffer {
- struct nvmap_handle_ref *mem; /* handle to pushbuffer memory */
- u32 *mapped; /* mapped gather buffer (at channel offset */
- u32 phys; /* physical address (at channel offset) */
- u32 incr_per_buffer; /* max # of incrs per GATHER */
- u32 words_per_incr; /* # of DWORDS in buffer to incr a syncpt */
+ struct mem_mgr_handle *client_handle; /* handle for each opcode pair */
};
struct buffer_timeout {
@@ -97,29 +82,28 @@ struct nvhost_cdma {
unsigned int first_get; /* DMAGET value, where submit begins */
unsigned int last_put; /* last value written to DMAPUT */
struct push_buffer push_buffer; /* channel's push buffer */
- struct syncpt_buffer syncpt_buffer; /* syncpt incr buffer */
struct list_head sync_queue; /* job queue */
struct buffer_timeout timeout; /* channel's timeout state/wq */
bool running;
bool torndown;
+ int high_prio_count;
+ int med_prio_count;
+ int low_prio_count;
};
#define cdma_to_channel(cdma) container_of(cdma, struct nvhost_channel, cdma)
#define cdma_to_dev(cdma) nvhost_get_host(cdma_to_channel(cdma)->dev)
-#define cdma_op(cdma) (cdma_to_dev(cdma)->op.cdma)
-#define cdma_to_nvmap(cdma) ((cdma_to_dev(cdma))->nvmap)
+#define cdma_to_memmgr(cdma) ((cdma_to_dev(cdma))->memmgr)
#define pb_to_cdma(pb) container_of(pb, struct nvhost_cdma, push_buffer)
-#define cdma_pb_op(cdma) (cdma_to_dev(cdma)->op.push_buffer)
int nvhost_cdma_init(struct nvhost_cdma *cdma);
void nvhost_cdma_deinit(struct nvhost_cdma *cdma);
void nvhost_cdma_stop(struct nvhost_cdma *cdma);
int nvhost_cdma_begin(struct nvhost_cdma *cdma, struct nvhost_job *job);
void nvhost_cdma_push(struct nvhost_cdma *cdma, u32 op1, u32 op2);
-#define NVHOST_CDMA_PUSH_GATHER_CTXSAVE 0xffffffff
void nvhost_cdma_push_gather(struct nvhost_cdma *cdma,
- struct nvmap_client *client,
- struct nvmap_handle *handle, u32 op1, u32 op2);
+ struct mem_mgr *client,
+ struct mem_handle *handle, u32 offset, u32 op1, u32 op2);
void nvhost_cdma_end(struct nvhost_cdma *cdma,
struct nvhost_job *job);
void nvhost_cdma_update(struct nvhost_cdma *cdma);
@@ -129,5 +113,5 @@ void nvhost_cdma_peek(struct nvhost_cdma *cdma,
unsigned int nvhost_cdma_wait_locked(struct nvhost_cdma *cdma,
enum cdma_event event);
void nvhost_cdma_update_sync_queue(struct nvhost_cdma *cdma,
- struct nvhost_syncpt *syncpt, struct device *dev);
+ struct nvhost_syncpt *syncpt, struct nvhost_device *dev);
#endif
diff --git a/drivers/video/tegra/host/nvhost_channel.c b/drivers/video/tegra/host/nvhost_channel.c
index afbac6fe4c4e..fd309ee9917b 100644
--- a/drivers/video/tegra/host/nvhost_channel.c
+++ b/drivers/video/tegra/host/nvhost_channel.c
@@ -20,13 +20,14 @@
#include "nvhost_channel.h"
#include "dev.h"
+#include "nvhost_acm.h"
#include "nvhost_job.h"
+#include "chip_support.h"
+
#include <trace/events/nvhost.h>
#include <linux/nvhost_ioctl.h>
#include <linux/slab.h>
-#include <linux/platform_device.h>
-
#define NVHOST_CHANNEL_LOW_PRIO_MAX_WAIT 50
int nvhost_channel_init(struct nvhost_channel *ch,
@@ -36,7 +37,7 @@ int nvhost_channel_init(struct nvhost_channel *ch,
struct nvhost_device *ndev;
/* Link nvhost_device to nvhost_channel */
- err = host_channel_op(dev).init(ch, dev, index);
+ err = channel_op().init(ch, dev, index);
if (err < 0) {
dev_err(&dev->dev->dev, "failed to init channel %d\n",
index);
@@ -50,23 +51,41 @@ int nvhost_channel_init(struct nvhost_channel *ch,
int nvhost_channel_submit(struct nvhost_job *job)
{
- /* Low priority submits wait until sync queue is empty. Ignores result
- * from nvhost_cdma_flush, as we submit either when push buffer is
- * empty or when we reach the timeout. */
- if (job->priority < NVHOST_PRIORITY_MEDIUM)
+ /*
+ * Check if queue has higher priority jobs running. If so, wait until
+ * queue is empty. Ignores result from nvhost_cdma_flush, as we submit
+ * either when push buffer is empty or when we reach the timeout.
+ */
+ int higher_count = 0;
+
+ switch (job->priority) {
+ case NVHOST_PRIORITY_HIGH:
+ higher_count = 0;
+ break;
+ case NVHOST_PRIORITY_MEDIUM:
+ higher_count = job->ch->cdma.high_prio_count;
+ break;
+ case NVHOST_PRIORITY_LOW:
+ higher_count = job->ch->cdma.high_prio_count
+ + job->ch->cdma.med_prio_count;
+ break;
+ }
+ if (higher_count > 0)
(void)nvhost_cdma_flush(&job->ch->cdma,
NVHOST_CHANNEL_LOW_PRIO_MAX_WAIT);
- return channel_op(job->ch).submit(job);
+ return channel_op().submit(job);
}
struct nvhost_channel *nvhost_getchannel(struct nvhost_channel *ch)
{
int err = 0;
+ struct nvhost_driver *drv = to_nvhost_driver(ch->dev->dev.driver);
+
mutex_lock(&ch->reflock);
if (ch->refcount == 0) {
- if (ch->dev->init)
- ch->dev->init(ch->dev);
+ if (drv->init)
+ drv->init(ch->dev);
err = nvhost_cdma_init(&ch->cdma);
} else if (ch->dev->exclusive) {
err = -EBUSY;
@@ -85,7 +104,7 @@ struct nvhost_channel *nvhost_getchannel(struct nvhost_channel *ch)
void nvhost_putchannel(struct nvhost_channel *ch, struct nvhost_hwctx *ctx)
{
- BUG_ON(!channel_cdma_op(ch).stop);
+ BUG_ON(!channel_cdma_op().stop);
if (ctx) {
mutex_lock(&ch->submitlock);
@@ -100,7 +119,7 @@ void nvhost_putchannel(struct nvhost_channel *ch, struct nvhost_hwctx *ctx)
mutex_lock(&ch->reflock);
if (ch->refcount == 1) {
- channel_cdma_op(ch).stop(&ch->cdma);
+ channel_cdma_op().stop(&ch->cdma);
nvhost_cdma_deinit(&ch->cdma);
nvhost_module_suspend(ch->dev);
}
@@ -113,14 +132,57 @@ int nvhost_channel_suspend(struct nvhost_channel *ch)
int ret = 0;
mutex_lock(&ch->reflock);
- BUG_ON(!channel_cdma_op(ch).stop);
+ BUG_ON(!channel_cdma_op().stop);
if (ch->refcount) {
ret = nvhost_module_suspend(ch->dev);
if (!ret)
- channel_cdma_op(ch).stop(&ch->cdma);
+ channel_cdma_op().stop(&ch->cdma);
}
mutex_unlock(&ch->reflock);
return ret;
}
+
+struct nvhost_channel *nvhost_alloc_channel_internal(int chindex,
+ int max_channels, int *current_channel_count)
+{
+ struct nvhost_channel *ch = NULL;
+
+ if ( (chindex > max_channels) ||
+ ( (*current_channel_count + 1) > max_channels) )
+ return NULL;
+ else {
+ ch = kzalloc(sizeof(*ch), GFP_KERNEL);
+ if (ch == NULL)
+ return NULL;
+ else {
+ (*current_channel_count)++;
+ return ch;
+ }
+ }
+}
+
+void nvhost_free_channel_internal(struct nvhost_channel *ch,
+ int *current_channel_count)
+{
+ kfree(ch);
+ (*current_channel_count)--;
+}
+
+int nvhost_channel_save_context(struct nvhost_channel *ch)
+{
+ struct nvhost_hwctx *cur_ctx = ch->cur_ctx;
+ int err = 0;
+ if (cur_ctx)
+ err = channel_op().save_context(ch);
+
+ return err;
+
+}
+
+int nvhost_channel_drain_read_fifo(struct nvhost_channel *ch,
+ u32 *ptr, unsigned int count, unsigned int *pending)
+{
+ return channel_op().drain_read_fifo(ch, ptr, count, pending);
+}
diff --git a/drivers/video/tegra/host/nvhost_channel.h b/drivers/video/tegra/host/nvhost_channel.h
index 7b946c8ee853..d7f096db1ffa 100644
--- a/drivers/video/tegra/host/nvhost_channel.h
+++ b/drivers/video/tegra/host/nvhost_channel.h
@@ -21,29 +21,19 @@
#ifndef __NVHOST_CHANNEL_H
#define __NVHOST_CHANNEL_H
-#include "nvhost_cdma.h"
-#include "nvhost_acm.h"
-#include "nvhost_hwctx.h"
-#include "nvhost_job.h"
-
#include <linux/cdev.h>
#include <linux/io.h>
+#include "nvhost_cdma.h"
-#define NVHOST_MAX_WAIT_CHECKS 256
-#define NVHOST_MAX_GATHERS 512
-#define NVHOST_MAX_HANDLES 1280
-#define NVHOST_MAX_POWERGATE_IDS 2
+#define NVHOST_MAX_WAIT_CHECKS 256
+#define NVHOST_MAX_GATHERS 512
+#define NVHOST_MAX_HANDLES 1280
+#define NVHOST_MAX_POWERGATE_IDS 2
struct nvhost_master;
-struct nvhost_waitchk;
struct nvhost_device;
-
-struct nvhost_channel_gather {
- u32 words;
- phys_addr_t mem;
- u32 mem_id;
- int offset;
-};
+struct nvhost_channel;
+struct nvhost_hwctx;
struct nvhost_channel {
int refcount;
@@ -60,8 +50,7 @@ struct nvhost_channel {
struct nvhost_cdma cdma;
};
-int nvhost_channel_init(
- struct nvhost_channel *ch,
+int nvhost_channel_init(struct nvhost_channel *ch,
struct nvhost_master *dev, int index);
int nvhost_channel_submit(struct nvhost_job *job);
@@ -70,17 +59,19 @@ struct nvhost_channel *nvhost_getchannel(struct nvhost_channel *ch);
void nvhost_putchannel(struct nvhost_channel *ch, struct nvhost_hwctx *ctx);
int nvhost_channel_suspend(struct nvhost_channel *ch);
-#define channel_cdma_op(ch) (nvhost_get_host(ch->dev)->op.cdma)
-#define channel_op(ch) (nvhost_get_host(ch->dev)->op.channel)
-#define host_channel_op(host) (host->op.channel)
-
-int nvhost_channel_drain_read_fifo(void __iomem *chan_regs,
+int nvhost_channel_drain_read_fifo(struct nvhost_channel *ch,
u32 *ptr, unsigned int count, unsigned int *pending);
-int nvhost_channel_read_3d_reg(
- struct nvhost_channel *channel,
+int nvhost_channel_read_3d_reg(struct nvhost_channel *channel,
struct nvhost_hwctx *hwctx,
- u32 offset,
- u32 *value);
+ u32 offset, u32 *value);
+
+struct nvhost_channel *nvhost_alloc_channel_internal(int chindex,
+ int max_channels, int *current_channel_count);
+
+void nvhost_free_channel_internal(struct nvhost_channel *ch,
+ int *current_channel_count);
+
+int nvhost_channel_save_context(struct nvhost_channel *ch);
#endif
diff --git a/drivers/video/tegra/host/nvhost_hwctx.h b/drivers/video/tegra/host/nvhost_hwctx.h
index 02a3976f01ce..47bc3d408fde 100644
--- a/drivers/video/tegra/host/nvhost_hwctx.h
+++ b/drivers/video/tegra/host/nvhost_hwctx.h
@@ -25,7 +25,6 @@
#include <linux/kref.h>
#include <linux/nvhost.h>
-#include <mach/nvmap.h>
struct nvhost_channel;
struct nvhost_cdma;
diff --git a/drivers/video/tegra/host/nvhost_intr.c b/drivers/video/tegra/host/nvhost_intr.c
index 7c4bdc7bafb6..38a04f151e87 100644
--- a/drivers/video/tegra/host/nvhost_intr.c
+++ b/drivers/video/tegra/host/nvhost_intr.c
@@ -20,14 +20,14 @@
#include "nvhost_intr.h"
#include "dev.h"
+#include "nvhost_acm.h"
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/irq.h>
#include <trace/events/nvhost.h>
-
-
-
-
+#include "nvhost_channel.h"
+#include "nvhost_hwctx.h"
+#include "chip_support.h"
/*** Wait list management ***/
@@ -116,11 +116,11 @@ void reset_threshold_interrupt(struct nvhost_intr *intr,
{
u32 thresh = list_first_entry(head,
struct nvhost_waitlist, list)->thresh;
- BUG_ON(!(intr_op(intr).set_syncpt_threshold &&
- intr_op(intr).enable_syncpt_intr));
+ BUG_ON(!(intr_op().set_syncpt_threshold &&
+ intr_op().enable_syncpt_intr));
- intr_op(intr).set_syncpt_threshold(intr, id, thresh);
- intr_op(intr).enable_syncpt_intr(intr, id);
+ intr_op().set_syncpt_threshold(intr, id, thresh);
+ intr_op().enable_syncpt_intr(intr, id);
}
@@ -129,12 +129,16 @@ static void action_submit_complete(struct nvhost_waitlist *waiter)
struct nvhost_channel *channel = waiter->data;
int nr_completed = waiter->count;
+ nvhost_cdma_update(&channel->cdma);
+ nvhost_module_idle_mult(channel->dev, nr_completed);
+
/* Add nr_completed to trace */
trace_nvhost_channel_submit_complete(channel->dev->name,
- nr_completed, waiter->thresh);
+ nr_completed, waiter->thresh,
+ channel->cdma.high_prio_count,
+ channel->cdma.med_prio_count,
+ channel->cdma.low_prio_count);
- nvhost_cdma_update(&channel->cdma);
- nvhost_module_idle_mult(channel->dev, nr_completed);
}
static void action_ctxsave(struct nvhost_waitlist *waiter)
@@ -264,8 +268,8 @@ int nvhost_intr_add_action(struct nvhost_intr *intr, u32 id, u32 thresh,
BUG_ON(waiter == NULL);
- BUG_ON(!(intr_op(intr).set_syncpt_threshold &&
- intr_op(intr).enable_syncpt_intr));
+ BUG_ON(!(intr_op().set_syncpt_threshold &&
+ intr_op().enable_syncpt_intr));
/* initialize a new waiter */
INIT_LIST_HEAD(&waiter->list);
@@ -278,7 +282,6 @@ int nvhost_intr_add_action(struct nvhost_intr *intr, u32 id, u32 thresh,
waiter->data = data;
waiter->count = 1;
- BUG_ON(id >= intr_to_dev(intr)->syncpt.nb_pts);
syncpt = intr->syncpt + id;
spin_lock(&syncpt->lock);
@@ -288,8 +291,8 @@ int nvhost_intr_add_action(struct nvhost_intr *intr, u32 id, u32 thresh,
spin_unlock(&syncpt->lock);
mutex_lock(&intr->mutex);
- BUG_ON(!(intr_op(intr).request_syncpt_irq));
- err = intr_op(intr).request_syncpt_irq(syncpt);
+ BUG_ON(!(intr_op().request_syncpt_irq));
+ err = intr_op().request_syncpt_irq(syncpt);
mutex_unlock(&intr->mutex);
if (err) {
@@ -304,11 +307,11 @@ int nvhost_intr_add_action(struct nvhost_intr *intr, u32 id, u32 thresh,
if (add_waiter_to_queue(waiter, &syncpt->wait_head)) {
/* added at head of list - new threshold value */
- intr_op(intr).set_syncpt_threshold(intr, id, thresh);
+ intr_op().set_syncpt_threshold(intr, id, thresh);
/* added as first waiter - enable interrupt */
if (queue_was_empty)
- intr_op(intr).enable_syncpt_intr(intr, id);
+ intr_op().enable_syncpt_intr(intr, id);
}
spin_unlock(&syncpt->lock);
@@ -342,13 +345,15 @@ int nvhost_intr_init(struct nvhost_intr *intr, u32 irq_gen, u32 irq_sync)
{
unsigned int id;
struct nvhost_intr_syncpt *syncpt;
- struct nvhost_master *host =
- container_of(intr, struct nvhost_master, intr);
- u32 nb_pts = host->syncpt.nb_pts;
+ struct nvhost_master *host = intr_to_dev(intr);
+ u32 nb_pts = nvhost_syncpt_nb_pts(&host->syncpt);
mutex_init(&intr->mutex);
+ intr->host_syncpt_irq_base = irq_sync;
+ intr_op().init_host_sync(intr);
intr->host_general_irq = irq_gen;
intr->host_general_irq_requested = false;
+ intr_op().request_host_general_irq(intr);
for (id = 0, syncpt = intr->syncpt;
id < nb_pts;
@@ -374,17 +379,17 @@ void nvhost_intr_deinit(struct nvhost_intr *intr)
void nvhost_intr_start(struct nvhost_intr *intr, u32 hz)
{
- BUG_ON(!(intr_op(intr).init_host_sync &&
- intr_op(intr).set_host_clocks_per_usec &&
- intr_op(intr).request_host_general_irq));
+ BUG_ON(!(intr_op().init_host_sync &&
+ intr_op().set_host_clocks_per_usec &&
+ intr_op().request_host_general_irq));
mutex_lock(&intr->mutex);
- intr_op(intr).init_host_sync(intr);
- intr_op(intr).set_host_clocks_per_usec(intr,
+ intr_op().init_host_sync(intr);
+ intr_op().set_host_clocks_per_usec(intr,
(hz + 1000000 - 1)/1000000);
- intr_op(intr).request_host_general_irq(intr);
+ intr_op().request_host_general_irq(intr);
mutex_unlock(&intr->mutex);
}
@@ -393,14 +398,14 @@ void nvhost_intr_stop(struct nvhost_intr *intr)
{
unsigned int id;
struct nvhost_intr_syncpt *syncpt;
- u32 nb_pts = intr_to_dev(intr)->syncpt.nb_pts;
+ u32 nb_pts = nvhost_syncpt_nb_pts(&intr_to_dev(intr)->syncpt);
- BUG_ON(!(intr_op(intr).disable_all_syncpt_intrs &&
- intr_op(intr).free_host_general_irq));
+ BUG_ON(!(intr_op().disable_all_syncpt_intrs &&
+ intr_op().free_host_general_irq));
mutex_lock(&intr->mutex);
- intr_op(intr).disable_all_syncpt_intrs(intr);
+ intr_op().disable_all_syncpt_intrs(intr);
for (id = 0, syncpt = intr->syncpt;
id < nb_pts;
@@ -422,7 +427,7 @@ void nvhost_intr_stop(struct nvhost_intr *intr)
free_syncpt_irq(syncpt);
}
- intr_op(intr).free_host_general_irq(intr);
+ intr_op().free_host_general_irq(intr);
mutex_unlock(&intr->mutex);
}
diff --git a/drivers/video/tegra/host/nvhost_intr.h b/drivers/video/tegra/host/nvhost_intr.h
index 26ab04ebd4ab..cf0b6b9e8934 100644
--- a/drivers/video/tegra/host/nvhost_intr.h
+++ b/drivers/video/tegra/host/nvhost_intr.h
@@ -71,10 +71,10 @@ struct nvhost_intr {
struct nvhost_intr_syncpt *syncpt;
struct mutex mutex;
int host_general_irq;
+ int host_syncpt_irq_base;
bool host_general_irq_requested;
};
#define intr_to_dev(x) container_of(x, struct nvhost_master, intr)
-#define intr_op(intr) (intr_to_dev(intr)->op.intr)
#define intr_syncpt_to_intr(is) (is->intr)
/**
diff --git a/drivers/video/tegra/host/nvhost_job.c b/drivers/video/tegra/host/nvhost_job.c
index a4f0cfc44212..f93d7df1a552 100644
--- a/drivers/video/tegra/host/nvhost_job.c
+++ b/drivers/video/tegra/host/nvhost_job.c
@@ -22,138 +22,58 @@
#include <linux/kref.h>
#include <linux/err.h>
#include <linux/vmalloc.h>
-#include <mach/nvmap.h>
+#include <trace/events/nvhost.h>
#include "nvhost_channel.h"
#include "nvhost_job.h"
+#include "nvhost_hwctx.h"
+#include "nvhost_syncpt.h"
#include "dev.h"
+#include "nvhost_memmgr.h"
+#include "chip_support.h"
/* Magic to use to fill freed handle slots */
#define BAD_MAGIC 0xdeadbeef
static int job_size(struct nvhost_submit_hdr_ext *hdr)
{
- int num_pins = hdr ? (hdr->num_relocs + hdr->num_cmdbufs)*2 : 0;
+ int num_relocs = hdr ? hdr->num_relocs : 0;
int num_waitchks = hdr ? hdr->num_waitchks : 0;
+ int num_cmdbufs = hdr ? hdr->num_cmdbufs : 0;
+ int num_unpins = num_cmdbufs + num_relocs;
return sizeof(struct nvhost_job)
- + num_pins * sizeof(struct nvmap_pinarray_elem)
- + num_pins * sizeof(struct nvmap_handle *)
- + num_waitchks * sizeof(struct nvhost_waitchk);
-}
-
-static int gather_size(int num_cmdbufs)
-{
- return num_cmdbufs * sizeof(struct nvhost_channel_gather);
-}
-
-static void free_gathers(struct nvhost_job *job)
-{
- if (job->gathers) {
- nvmap_munmap(job->gather_mem, job->gathers);
- job->gathers = NULL;
- }
- if (job->gather_mem) {
- nvmap_free(job->nvmap, job->gather_mem);
- job->gather_mem = NULL;
- }
-}
-
-static int alloc_gathers(struct nvhost_job *job,
- int num_cmdbufs)
-{
- int err = 0;
-
- job->gather_mem = NULL;
- job->gathers = NULL;
- job->gather_mem_size = 0;
-
- if (num_cmdbufs) {
- /* Allocate memory */
- job->gather_mem = nvmap_alloc(job->nvmap,
- gather_size(num_cmdbufs),
- 32, NVMAP_HANDLE_CACHEABLE, 0);
- if (IS_ERR_OR_NULL(job->gather_mem)) {
- err = job->gather_mem ? PTR_ERR(job->gather_mem) : -ENOMEM;
- job->gather_mem = NULL;
- goto error;
- }
- job->gather_mem_size = gather_size(num_cmdbufs);
-
- /* Map memory to kernel */
- job->gathers = nvmap_mmap(job->gather_mem);
- if (IS_ERR_OR_NULL(job->gathers)) {
- err = job->gathers ? PTR_ERR(job->gathers) : -ENOMEM;
- job->gathers = NULL;
- goto error;
- }
- }
-
- return 0;
-
-error:
- free_gathers(job);
- return err;
-}
-
-static int realloc_gathers(struct nvhost_job *oldjob,
- struct nvhost_job *newjob,
- int num_cmdbufs)
-{
- int err = 0;
-
- /* Check if we can reuse gather buffer */
- if (oldjob->gather_mem_size < gather_size(num_cmdbufs)
- || oldjob->nvmap != newjob->nvmap) {
- free_gathers(oldjob);
- err = alloc_gathers(newjob, num_cmdbufs);
- } else {
- newjob->gather_mem = oldjob->gather_mem;
- newjob->gathers = oldjob->gathers;
- newjob->gather_mem_size = oldjob->gather_mem_size;
-
- oldjob->gather_mem = NULL;
- oldjob->gathers = NULL;
- oldjob->gather_mem_size = 0;
- }
- return err;
+ + num_relocs * sizeof(struct nvhost_reloc)
+ + num_relocs * sizeof(struct nvhost_reloc_shift)
+ + num_unpins * sizeof(struct mem_handle *)
+ + num_waitchks * sizeof(struct nvhost_waitchk)
+ + num_cmdbufs * sizeof(struct nvhost_job_gather);
}
static void init_fields(struct nvhost_job *job,
struct nvhost_submit_hdr_ext *hdr,
int priority, int clientid)
{
- int num_pins = hdr ? (hdr->num_relocs + hdr->num_cmdbufs)*2 : 0;
+ int num_relocs = hdr ? hdr->num_relocs : 0;
int num_waitchks = hdr ? hdr->num_waitchks : 0;
+ int num_cmdbufs = hdr ? hdr->num_cmdbufs : 0;
+ int num_unpins = num_cmdbufs + num_relocs;
void *mem = job;
/* First init state to zero */
- job->num_gathers = 0;
- job->num_pins = 0;
- job->num_unpins = 0;
- job->num_waitchk = 0;
- job->waitchk_mask = 0;
- job->syncpt_id = 0;
- job->syncpt_incrs = 0;
- job->syncpt_end = 0;
job->priority = priority;
job->clientid = clientid;
- job->null_kickoff = false;
- job->first_get = 0;
- job->num_slots = 0;
/* Redistribute memory to the structs */
mem += sizeof(struct nvhost_job);
- if (num_pins) {
- job->pinarray = mem;
- mem += num_pins * sizeof(struct nvmap_pinarray_elem);
- job->unpins = mem;
- mem += num_pins * sizeof(struct nvmap_handle *);
- } else {
- job->pinarray = NULL;
- job->unpins = NULL;
- }
-
+ job->relocarray = num_relocs ? mem : NULL;
+ mem += num_relocs * sizeof(struct nvhost_reloc);
+ job->relocshiftarray = num_relocs ? mem : NULL;
+ mem += num_relocs * sizeof(struct nvhost_reloc_shift);
+ job->unpins = num_unpins ? mem : NULL;
+ mem += num_unpins * sizeof(struct mem_handle *);
job->waitchk = num_waitchks ? mem : NULL;
+ mem += num_waitchks * sizeof(struct nvhost_waitchk);
+ job->gathers = num_cmdbufs ? mem : NULL;
/* Copy information from header */
if (hdr) {
@@ -166,13 +86,11 @@ static void init_fields(struct nvhost_job *job,
struct nvhost_job *nvhost_job_alloc(struct nvhost_channel *ch,
struct nvhost_hwctx *hwctx,
struct nvhost_submit_hdr_ext *hdr,
- struct nvmap_client *nvmap,
+ struct mem_mgr *memmgr,
int priority,
int clientid)
{
struct nvhost_job *job = NULL;
- int num_cmdbufs = hdr ? hdr->num_cmdbufs : 0;
- int err = 0;
job = vzalloc(job_size(hdr));
if (!job)
@@ -183,11 +101,7 @@ struct nvhost_job *nvhost_job_alloc(struct nvhost_channel *ch,
job->hwctx = hwctx;
if (hwctx)
hwctx->h->get(hwctx);
- job->nvmap = nvmap ? nvmap_client_get(nvmap) : NULL;
-
- err = alloc_gathers(job, num_cmdbufs);
- if (err)
- goto error;
+ job->memmgr = memmgr ? mem_op().get_mgr(memmgr) : NULL;
init_fields(job, hdr, priority, clientid);
@@ -199,46 +113,6 @@ error:
return NULL;
}
-struct nvhost_job *nvhost_job_realloc(
- struct nvhost_job *oldjob,
- struct nvhost_hwctx *hwctx,
- struct nvhost_submit_hdr_ext *hdr,
- struct nvmap_client *nvmap,
- int priority, int clientid)
-{
- struct nvhost_job *newjob = NULL;
- int num_cmdbufs = hdr ? hdr->num_cmdbufs : 0;
- int err = 0;
-
- newjob = vzalloc(job_size(hdr));
- if (!newjob)
- goto error;
- kref_init(&newjob->ref);
- newjob->ch = oldjob->ch;
- newjob->hwctx = hwctx;
- if (hwctx)
- newjob->hwctx->h->get(newjob->hwctx);
- newjob->timeout = oldjob->timeout;
- newjob->nvmap = nvmap ? nvmap_client_get(nvmap) : NULL;
-
- err = realloc_gathers(oldjob, newjob, num_cmdbufs);
- if (err)
- goto error;
-
- nvhost_job_put(oldjob);
-
- init_fields(newjob, hdr, priority, clientid);
-
- return newjob;
-
-error:
- if (newjob)
- nvhost_job_put(newjob);
- if (oldjob)
- nvhost_job_put(oldjob);
- return NULL;
-}
-
void nvhost_job_get(struct nvhost_job *job)
{
kref_get(&job->ref);
@@ -252,12 +126,8 @@ static void job_free(struct kref *ref)
job->hwctxref->h->put(job->hwctxref);
if (job->hwctx)
job->hwctx->h->put(job->hwctx);
- if (job->gathers)
- nvmap_munmap(job->gather_mem, job->gathers);
- if (job->gather_mem)
- nvmap_free(job->nvmap, job->gather_mem);
- if (job->nvmap)
- nvmap_client_put(job->nvmap);
+ if (job->memmgr)
+ mem_op().put_mgr(job->memmgr);
vfree(job);
}
@@ -279,42 +149,176 @@ void nvhost_job_put(struct nvhost_job *job)
void nvhost_job_add_gather(struct nvhost_job *job,
u32 mem_id, u32 words, u32 offset)
{
- struct nvmap_pinarray_elem *pin;
- struct nvhost_channel_gather *cur_gather =
+ struct nvhost_job_gather *cur_gather =
&job->gathers[job->num_gathers];
- pin = &job->pinarray[job->num_pins++];
- pin->patch_mem = (u32)nvmap_ref_to_handle(job->gather_mem);
- pin->patch_offset = (void *)&(cur_gather->mem) - (void *)job->gathers;
- pin->pin_mem = nvmap_convert_handle_u2k(mem_id);
- pin->pin_offset = offset;
cur_gather->words = words;
cur_gather->mem_id = mem_id;
cur_gather->offset = offset;
job->num_gathers += 1;
}
-int nvhost_job_pin(struct nvhost_job *job)
+static int do_relocs(struct nvhost_job *job, u32 cmdbuf_mem, void *cmdbuf_addr)
+{
+ phys_addr_t target_phys = -EINVAL;
+ int i;
+ u32 mem_id = 0;
+ struct mem_handle *target_ref = NULL;
+
+ /* pin & patch the relocs for one gather */
+ for (i = 0; i < job->num_relocs; i++) {
+ struct nvhost_reloc *reloc = &job->relocarray[i];
+ struct nvhost_reloc_shift *shift = &job->relocshiftarray[i];
+
+ /* skip all other gathers */
+ if (cmdbuf_mem != reloc->cmdbuf_mem)
+ continue;
+
+ /* check if pin-mem is same as previous */
+ if (reloc->target != mem_id) {
+ target_ref = mem_op().get(job->memmgr, reloc->target);
+ if (IS_ERR(target_ref))
+ return PTR_ERR(target_ref);
+
+ target_phys = mem_op().pin(job->memmgr, target_ref);
+ if (IS_ERR((void *)target_phys)) {
+ mem_op().put(job->memmgr, target_ref);
+ return target_phys;
+ }
+
+ mem_id = reloc->target;
+ job->unpins[job->num_unpins++] = target_ref;
+ }
+
+ __raw_writel(
+ (target_phys + reloc->target_offset) >> shift->shift,
+ (cmdbuf_addr + reloc->cmdbuf_offset));
+
+ /* Different gathers might have same mem_id. This ensures we
+ * perform reloc only once per gather memid. */
+ reloc->cmdbuf_mem = 0;
+ }
+
+ return 0;
+}
+
+/*
+ * Check driver supplied waitchk structs for syncpt thresholds
+ * that have already been satisfied and NULL the comparison (to
+ * avoid a wrap condition in the HW).
+ */
+static int do_waitchks(struct nvhost_job *job, struct nvhost_syncpt *sp,
+ u32 patch_mem, void *patch_addr)
{
- int err = 0;
+ int i;
+
+ /* compare syncpt vs wait threshold */
+ for (i = 0; i < job->num_waitchk; i++) {
+ struct nvhost_waitchk *wait = &job->waitchk[i];
+
+ /* skip all other gathers */
+ if (patch_mem != wait->mem)
+ continue;
+
+ trace_nvhost_syncpt_wait_check(wait->mem, wait->offset,
+ wait->syncpt_id, wait->thresh,
+ nvhost_syncpt_read(sp, wait->syncpt_id));
+ if (nvhost_syncpt_is_expired(sp,
+ wait->syncpt_id, wait->thresh)) {
+ /*
+ * NULL an already satisfied WAIT_SYNCPT host method,
+ * by patching its args in the command stream. The
+ * method data is changed to reference a reserved
+ * (never given out or incr) NVSYNCPT_GRAPHICS_HOST
+ * syncpt with a matching threshold value of 0, so
+ * is guaranteed to be popped by the host HW.
+ */
+ dev_dbg(&syncpt_to_dev(sp)->dev->dev,
+ "drop WAIT id %d (%s) thresh 0x%x, min 0x%x\n",
+ wait->syncpt_id,
+ syncpt_op().name(sp, wait->syncpt_id),
+ wait->thresh,
+ nvhost_syncpt_read_min(sp, wait->syncpt_id));
+
+ /* patch the wait */
+ nvhost_syncpt_patch_wait(sp,
+ (patch_addr + wait->offset));
+ }
+
+ wait->mem = 0;
+ }
+ return 0;
+}
- /* pin mem handles and patch physical addresses */
- job->num_unpins = nvmap_pin_array(job->nvmap,
- nvmap_ref_to_handle(job->gather_mem),
- job->pinarray, job->num_pins,
- job->unpins);
- if (job->num_unpins < 0)
- err = job->num_unpins;
+int nvhost_job_pin(struct nvhost_job *job, struct nvhost_syncpt *sp)
+{
+ int err = 0, i = 0;
+ phys_addr_t gather_phys = 0;
+ void *gather_addr = NULL;
+ unsigned long waitchk_mask = job->waitchk_mask;
+
+ /* get current syncpt values for waitchk */
+ for_each_set_bit(i, &waitchk_mask, sizeof(job->waitchk_mask))
+ nvhost_syncpt_update_min(sp, i);
+
+ /* pin gathers */
+ for (i = 0; i < job->num_gathers; i++) {
+ struct nvhost_job_gather *g = &job->gathers[i];
+
+ /* process each gather mem only once */
+ if (!g->ref) {
+ g->ref = mem_op().get(job->memmgr,
+ job->gathers[i].mem_id);
+ if (IS_ERR(g->ref)) {
+ err = PTR_ERR(g->ref);
+ g->ref = NULL;
+ break;
+ }
+
+ gather_phys = mem_op().pin(job->memmgr, g->ref);
+ if (IS_ERR((void *)gather_phys)) {
+ mem_op().put(job->memmgr, g->ref);
+ err = gather_phys;
+ break;
+ }
+
+ /* store the gather ref into unpin array */
+ job->unpins[job->num_unpins++] = g->ref;
+
+ gather_addr = mem_op().mmap(g->ref);
+ if (!gather_addr) {
+ err = -ENOMEM;
+ break;
+ }
+
+ err = do_relocs(job, g->mem_id, gather_addr);
+ if (!err)
+ err = do_waitchks(job, sp,
+ g->mem_id, gather_addr);
+ mem_op().munmap(g->ref, gather_addr);
+
+ if (err)
+ break;
+ }
+ g->mem = gather_phys + g->offset;
+ }
+ wmb();
return err;
}
void nvhost_job_unpin(struct nvhost_job *job)
{
- nvmap_unpin_handles(job->nvmap, job->unpins,
- job->num_unpins);
+ int i;
+
+ for (i = 0; i < job->num_unpins; i++) {
+ mem_op().unpin(job->memmgr, job->unpins[i]);
+ mem_op().put(job->memmgr, job->unpins[i]);
+ }
+
memset(job->unpins, BAD_MAGIC,
- job->num_unpins * sizeof(struct nvmap_handle *));
+ job->num_unpins * sizeof(struct mem_handle *));
+ job->num_unpins = 0;
}
/**
diff --git a/drivers/video/tegra/host/nvhost_job.h b/drivers/video/tegra/host/nvhost_job.h
index ad9d1af60da1..3b444579c543 100644
--- a/drivers/video/tegra/host/nvhost_job.h
+++ b/drivers/video/tegra/host/nvhost_job.h
@@ -25,9 +25,16 @@
struct nvhost_channel;
struct nvhost_hwctx;
-struct nvmap_client;
struct nvhost_waitchk;
-struct nvmap_handle;
+struct nvhost_syncpt;
+
+struct nvhost_job_gather {
+ u32 words;
+ phys_addr_t mem;
+ u32 mem_id;
+ int offset;
+ struct mem_handle *ref;
+};
/*
* Each submit is tracked as a nvhost_job.
@@ -47,13 +54,11 @@ struct nvhost_job {
int clientid;
/* Nvmap to be used for pinning & unpinning memory */
- struct nvmap_client *nvmap;
+ struct mem_mgr *memmgr;
/* Gathers and their memory */
- struct nvmap_handle_ref *gather_mem;
- struct nvhost_channel_gather *gathers;
+ struct nvhost_job_gather *gathers;
int num_gathers;
- int gather_mem_size;
/* Wait checks to be processed at submit time */
struct nvhost_waitchk *waitchk;
@@ -61,9 +66,10 @@ struct nvhost_job {
u32 waitchk_mask;
/* Array of handles to be pinned & unpinned */
- struct nvmap_pinarray_elem *pinarray;
- int num_pins;
- struct nvmap_handle **unpins;
+ struct nvhost_reloc *relocarray;
+ struct nvhost_reloc_shift *relocshiftarray;
+ int num_relocs;
+ struct mem_handle **unpins;
int num_unpins;
/* Sync point id, number of increments and end related to the submit */
@@ -95,18 +101,7 @@ struct nvhost_job {
struct nvhost_job *nvhost_job_alloc(struct nvhost_channel *ch,
struct nvhost_hwctx *hwctx,
struct nvhost_submit_hdr_ext *hdr,
- struct nvmap_client *nvmap,
- int priority, int clientid);
-
-/*
- * Allocate memory for a job. Just enough memory will be allocated to
- * accomodate the submit announced in submit header. Gather memory from
- * oldjob will be reused, and nvhost_job_put() will be called to it.
- */
-struct nvhost_job *nvhost_job_realloc(struct nvhost_job *oldjob,
- struct nvhost_hwctx *hwctx,
- struct nvhost_submit_hdr_ext *hdr,
- struct nvmap_client *nvmap,
+ struct mem_mgr *memmgr,
int priority, int clientid);
/*
@@ -134,8 +129,11 @@ void nvhost_job_put(struct nvhost_job *job);
* Pin memory related to job. This handles relocation of addresses to the
* host1x address space. Handles both the gather memory and any other memory
* referred to from the gather buffers.
+ *
+ * Handles also patching out host waits that would wait for an expired sync
+ * point value.
*/
-int nvhost_job_pin(struct nvhost_job *job);
+int nvhost_job_pin(struct nvhost_job *job, struct nvhost_syncpt *sp);
/*
* Unpin memory related to job.
diff --git a/drivers/video/tegra/host/nvhost_memmgr.c b/drivers/video/tegra/host/nvhost_memmgr.c
new file mode 100644
index 000000000000..f530c2e63006
--- /dev/null
+++ b/drivers/video/tegra/host/nvhost_memmgr.c
@@ -0,0 +1,34 @@
+/*
+ * drivers/video/tegra/host/nvhost_memmgr.c
+ *
+ * Tegra Graphics Host Memory Management Abstraction
+ *
+ * Copyright (c) 2012, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+
+#include "nvhost_memmgr.h"
+#include "nvmap.h"
+
+int nvhost_memmgr_init(struct nvhost_chip_support *chip)
+{
+#ifdef CONFIG_TEGRA_GRHOST_USE_NVMAP
+ return nvhost_init_nvmap_support(chip);
+#endif
+ BUG_ON(!"No memory manager selected");
+ return -ENODEV;
+}
diff --git a/drivers/video/tegra/host/nvhost_memmgr.h b/drivers/video/tegra/host/nvhost_memmgr.h
new file mode 100644
index 000000000000..d61379b6ff55
--- /dev/null
+++ b/drivers/video/tegra/host/nvhost_memmgr.h
@@ -0,0 +1,38 @@
+/*
+ * drivers/video/tegra/host/nvhost_memmgr.h
+ *
+ * Tegra Graphics Host Memory Management Abstraction header
+ *
+ * Copyright (c) 2012, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _NVHOST_MEM_MGR_H_
+#define _NVHOST_MEM_MGR_H_
+
+struct nvhost_chip_support;
+
+enum mem_mgr_flag {
+ mem_mgr_flag_uncacheable = 0,
+ mem_mgr_flag_write_combine = 1,
+};
+
+struct mem_mgr_handle {
+ struct mem_mgr *client;
+ struct mem_handle *handle;
+};
+
+int nvhost_memmgr_init(struct nvhost_chip_support *chip);
+
+#endif
diff --git a/drivers/video/tegra/host/nvhost_syncpt.c b/drivers/video/tegra/host/nvhost_syncpt.c
index 13ad0fc3a3cf..9fa7d0652c1f 100644
--- a/drivers/video/tegra/host/nvhost_syncpt.c
+++ b/drivers/video/tegra/host/nvhost_syncpt.c
@@ -21,10 +21,12 @@
#include <linux/nvhost_ioctl.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
+#include <trace/events/nvhost.h>
#include "nvhost_syncpt.h"
+#include "nvhost_acm.h"
#include "dev.h"
+#include "chip_support.h"
-#define MAX_STUCK_CHECK_COUNT 15
#define MAX_SYNCPT_LENGTH 5
/* Name of sysfs node for min and max value */
static const char *min_name = "min";
@@ -36,12 +38,12 @@ static const char *max_name = "max";
void nvhost_syncpt_reset(struct nvhost_syncpt *sp)
{
u32 i;
- BUG_ON(!(syncpt_op(sp).reset && syncpt_op(sp).reset_wait_base));
+ BUG_ON(!(syncpt_op().reset && syncpt_op().reset_wait_base));
- for (i = 0; i < sp->nb_pts; i++)
- syncpt_op(sp).reset(sp, i);
- for (i = 0; i < sp->nb_bases; i++)
- syncpt_op(sp).reset_wait_base(sp, i);
+ for (i = 0; i < nvhost_syncpt_nb_pts(sp); i++)
+ syncpt_op().reset(sp, i);
+ for (i = 0; i < nvhost_syncpt_nb_bases(sp); i++)
+ syncpt_op().reset_wait_base(sp, i);
wmb();
}
@@ -51,17 +53,17 @@ void nvhost_syncpt_reset(struct nvhost_syncpt *sp)
void nvhost_syncpt_save(struct nvhost_syncpt *sp)
{
u32 i;
- BUG_ON(!(syncpt_op(sp).update_min && syncpt_op(sp).read_wait_base));
+ BUG_ON(!(syncpt_op().update_min && syncpt_op().read_wait_base));
- for (i = 0; i < sp->nb_pts; i++) {
- if (client_managed(i))
- syncpt_op(sp).update_min(sp, i);
+ for (i = 0; i < nvhost_syncpt_nb_pts(sp); i++) {
+ if (nvhost_syncpt_client_managed(sp, i))
+ syncpt_op().update_min(sp, i);
else
BUG_ON(!nvhost_syncpt_min_eq_max(sp, i));
}
- for (i = 0; i < sp->nb_bases; i++)
- syncpt_op(sp).read_wait_base(sp, i);
+ for (i = 0; i < nvhost_syncpt_nb_bases(sp); i++)
+ syncpt_op().read_wait_base(sp, i);
}
/**
@@ -69,9 +71,14 @@ void nvhost_syncpt_save(struct nvhost_syncpt *sp)
*/
u32 nvhost_syncpt_update_min(struct nvhost_syncpt *sp, u32 id)
{
- BUG_ON(!syncpt_op(sp).update_min);
+ u32 val;
+
+ BUG_ON(!syncpt_op().update_min);
+
+ val = syncpt_op().update_min(sp, id);
+ trace_nvhost_syncpt_update_min(id, val);
- return syncpt_op(sp).update_min(sp, id);
+ return val;
}
/**
@@ -80,9 +87,9 @@ u32 nvhost_syncpt_update_min(struct nvhost_syncpt *sp, u32 id)
u32 nvhost_syncpt_read(struct nvhost_syncpt *sp, u32 id)
{
u32 val;
- BUG_ON(!syncpt_op(sp).update_min);
+ BUG_ON(!syncpt_op().update_min);
nvhost_module_busy(syncpt_to_dev(sp)->dev);
- val = syncpt_op(sp).update_min(sp, id);
+ val = syncpt_op().update_min(sp, id);
nvhost_module_idle(syncpt_to_dev(sp)->dev);
return val;
}
@@ -93,9 +100,9 @@ u32 nvhost_syncpt_read(struct nvhost_syncpt *sp, u32 id)
u32 nvhost_syncpt_read_wait_base(struct nvhost_syncpt *sp, u32 id)
{
u32 val;
- BUG_ON(!syncpt_op(sp).read_wait_base);
+ BUG_ON(!syncpt_op().read_wait_base);
nvhost_module_busy(syncpt_to_dev(sp)->dev);
- syncpt_op(sp).read_wait_base(sp, id);
+ syncpt_op().read_wait_base(sp, id);
val = sp->base_val[id];
nvhost_module_idle(syncpt_to_dev(sp)->dev);
return val;
@@ -107,8 +114,8 @@ u32 nvhost_syncpt_read_wait_base(struct nvhost_syncpt *sp, u32 id)
*/
void nvhost_syncpt_cpu_incr(struct nvhost_syncpt *sp, u32 id)
{
- BUG_ON(!syncpt_op(sp).cpu_incr);
- syncpt_op(sp).cpu_incr(sp, id);
+ BUG_ON(!syncpt_op().cpu_incr);
+ syncpt_op().cpu_incr(sp, id);
}
/**
@@ -116,7 +123,7 @@ void nvhost_syncpt_cpu_incr(struct nvhost_syncpt *sp, u32 id)
*/
void nvhost_syncpt_incr(struct nvhost_syncpt *sp, u32 id)
{
- if (client_managed(id))
+ if (nvhost_syncpt_client_managed(sp, id))
nvhost_syncpt_incr_max(sp, id, 1);
nvhost_module_busy(syncpt_to_dev(sp)->dev);
nvhost_syncpt_cpu_incr(sp, id);
@@ -124,6 +131,19 @@ void nvhost_syncpt_incr(struct nvhost_syncpt *sp, u32 id)
}
/**
+ * Updated sync point form hardware, and returns true if syncpoint is expired,
+ * false if we may need to wait
+ */
+static bool syncpt_update_min_is_expired(
+ struct nvhost_syncpt *sp,
+ u32 id,
+ u32 thresh)
+{
+ syncpt_op().update_min(sp, id);
+ return nvhost_syncpt_is_expired(sp, id, thresh);
+}
+
+/**
* Main entrypoint for syncpoint value waits.
*/
int nvhost_syncpt_wait_timeout(struct nvhost_syncpt *sp, u32 id,
@@ -149,7 +169,7 @@ int nvhost_syncpt_wait_timeout(struct nvhost_syncpt *sp, u32 id,
nvhost_module_busy(syncpt_to_dev(sp)->dev);
/* try to read from register */
- val = syncpt_op(sp).update_min(sp, id);
+ val = syncpt_op().update_min(sp, id);
if (nvhost_syncpt_is_expired(sp, id, thresh)) {
if (value)
*value = val;
@@ -184,9 +204,9 @@ int nvhost_syncpt_wait_timeout(struct nvhost_syncpt *sp, u32 id,
while (timeout) {
u32 check = min_t(u32, SYNCPT_CHECK_PERIOD, timeout);
int remain = wait_event_interruptible_timeout(wq,
- nvhost_syncpt_is_expired(sp, id, thresh),
+ syncpt_update_min_is_expired(sp, id, thresh),
check);
- if (remain > 0) {
+ if (remain > 0 || nvhost_syncpt_is_expired(sp, id, thresh)) {
if (value)
*value = nvhost_syncpt_read_min(sp, id);
err = 0;
@@ -198,20 +218,19 @@ int nvhost_syncpt_wait_timeout(struct nvhost_syncpt *sp, u32 id,
}
if (timeout != NVHOST_NO_TIMEOUT)
timeout -= check;
- if (timeout) {
+ if (timeout && check_count <= MAX_STUCK_CHECK_COUNT) {
dev_warn(&syncpt_to_dev(sp)->dev->dev,
"%s: syncpoint id %d (%s) stuck waiting %d, timeout=%d\n",
- current->comm, id, syncpt_op(sp).name(sp, id),
+ current->comm, id, syncpt_op().name(sp, id),
thresh, timeout);
- syncpt_op(sp).debug(sp);
- if (check_count > MAX_STUCK_CHECK_COUNT) {
+ syncpt_op().debug(sp);
+ if (check_count == MAX_STUCK_CHECK_COUNT) {
if (low_timeout) {
dev_warn(&syncpt_to_dev(sp)->dev->dev,
"is timeout %d too low?\n",
low_timeout);
}
nvhost_debug_dump(syncpt_to_dev(sp));
- BUG();
}
check_count++;
}
@@ -279,7 +298,7 @@ bool nvhost_syncpt_is_expired(
* If future valueis zero, we have a client managed sync point. In that
* case we do a direct comparison.
*/
- if (!client_managed(id))
+ if (!nvhost_syncpt_client_managed(sp, id))
return future_val - thresh >= current_val - thresh;
else
return (s32)(current_val - thresh) >= 0;
@@ -287,7 +306,7 @@ bool nvhost_syncpt_is_expired(
void nvhost_syncpt_debug(struct nvhost_syncpt *sp)
{
- syncpt_op(sp).debug(sp);
+ syncpt_op().debug(sp);
}
int nvhost_mutex_try_lock(struct nvhost_syncpt *sp, int idx)
@@ -296,7 +315,7 @@ int nvhost_mutex_try_lock(struct nvhost_syncpt *sp, int idx)
u32 reg;
nvhost_module_busy(host->dev);
- reg = syncpt_op(sp).mutex_try_lock(sp, idx);
+ reg = syncpt_op().mutex_try_lock(sp, idx);
if (reg) {
nvhost_module_idle(host->dev);
return -EBUSY;
@@ -307,20 +326,15 @@ int nvhost_mutex_try_lock(struct nvhost_syncpt *sp, int idx)
void nvhost_mutex_unlock(struct nvhost_syncpt *sp, int idx)
{
- syncpt_op(sp).mutex_unlock(sp, idx);
+ syncpt_op().mutex_unlock(sp, idx);
nvhost_module_idle(syncpt_to_dev(sp)->dev);
atomic_dec(&sp->lock_counts[idx]);
}
-/* check for old WAITs to be removed (avoiding a wrap) */
-int nvhost_syncpt_wait_check(struct nvhost_syncpt *sp,
- struct nvmap_client *nvmap,
- u32 waitchk_mask,
- struct nvhost_waitchk *wait,
- int num_waitchk)
+/* remove a wait pointed to by patch_addr */
+int nvhost_syncpt_patch_wait(struct nvhost_syncpt *sp, void *patch_addr)
{
- return syncpt_op(sp).wait_check(sp, nvmap,
- waitchk_mask, wait, num_waitchk);
+ return syncpt_op().patch_wait(sp, patch_addr);
}
/* Displays the current value of the sync point via sysfs */
@@ -354,10 +368,15 @@ int nvhost_syncpt_init(struct nvhost_device *dev,
int err = 0;
/* Allocate structs for min, max and base values */
- sp->min_val = kzalloc(sizeof(atomic_t) * sp->nb_pts, GFP_KERNEL);
- sp->max_val = kzalloc(sizeof(atomic_t) * sp->nb_pts, GFP_KERNEL);
- sp->base_val = kzalloc(sizeof(u32) * sp->nb_bases, GFP_KERNEL);
- sp->lock_counts = kzalloc(sizeof(atomic_t) * sp->nb_mlocks, GFP_KERNEL);
+ sp->min_val = kzalloc(sizeof(atomic_t) * nvhost_syncpt_nb_pts(sp),
+ GFP_KERNEL);
+ sp->max_val = kzalloc(sizeof(atomic_t) * nvhost_syncpt_nb_pts(sp),
+ GFP_KERNEL);
+ sp->base_val = kzalloc(sizeof(u32) * nvhost_syncpt_nb_bases(sp),
+ GFP_KERNEL);
+ sp->lock_counts =
+ kzalloc(sizeof(atomic_t) * nvhost_syncpt_nb_mlocks(sp),
+ GFP_KERNEL);
if (!(sp->min_val && sp->max_val && sp->base_val && sp->lock_counts)) {
/* frees happen in the deinit */
@@ -372,15 +391,15 @@ int nvhost_syncpt_init(struct nvhost_device *dev,
}
/* Allocate two attributes for each sync point: min and max */
- sp->syncpt_attrs = kzalloc(sizeof(*sp->syncpt_attrs) * sp->nb_pts * 2,
- GFP_KERNEL);
+ sp->syncpt_attrs = kzalloc(sizeof(*sp->syncpt_attrs)
+ * nvhost_syncpt_nb_pts(sp) * 2, GFP_KERNEL);
if (!sp->syncpt_attrs) {
err = -ENOMEM;
goto fail;
}
/* Fill in the attributes */
- for (i = 0; i < sp->nb_pts; i++) {
+ for (i = 0; i < nvhost_syncpt_nb_pts(sp); i++) {
char name[MAX_SYNCPT_LENGTH];
struct kobject *kobj;
struct nvhost_syncpt_attr *min = &sp->syncpt_attrs[i*2];
@@ -441,3 +460,49 @@ void nvhost_syncpt_deinit(struct nvhost_syncpt *sp)
kfree(sp->syncpt_attrs);
sp->syncpt_attrs = NULL;
}
+
+int nvhost_syncpt_client_managed(struct nvhost_syncpt *sp, u32 id)
+{
+ return BIT(id) & syncpt_to_dev(sp)->info.client_managed;
+}
+
+int nvhost_syncpt_nb_pts(struct nvhost_syncpt *sp)
+{
+ return syncpt_to_dev(sp)->info.nb_pts;
+}
+
+int nvhost_syncpt_nb_bases(struct nvhost_syncpt *sp)
+{
+ return syncpt_to_dev(sp)->info.nb_bases;
+}
+
+int nvhost_syncpt_nb_mlocks(struct nvhost_syncpt *sp)
+{
+ return syncpt_to_dev(sp)->info.nb_mlocks;
+}
+
+/* public sync point API */
+u32 nvhost_syncpt_incr_max_ext(struct nvhost_device *dev, u32 id, u32 incrs)
+{
+ struct nvhost_syncpt *sp = &(nvhost_get_host(dev)->syncpt);
+ return nvhost_syncpt_incr_max(sp, id, incrs);
+}
+
+void nvhost_syncpt_cpu_incr_ext(struct nvhost_device *dev, u32 id)
+{
+ struct nvhost_syncpt *sp = &(nvhost_get_host(dev)->syncpt);
+ nvhost_syncpt_cpu_incr(sp, id);
+}
+
+u32 nvhost_syncpt_read_ext(struct nvhost_device *dev, u32 id)
+{
+ struct nvhost_syncpt *sp = &(nvhost_get_host(dev)->syncpt);
+ return nvhost_syncpt_read(sp, id);
+}
+
+int nvhost_syncpt_wait_timeout_ext(struct nvhost_device *dev, u32 id, u32 thresh,
+ u32 timeout, u32 *value)
+{
+ struct nvhost_syncpt *sp = &(nvhost_get_host(dev)->syncpt);
+ return nvhost_syncpt_wait_timeout(sp, id, thresh, timeout, value);
+}
diff --git a/drivers/video/tegra/host/nvhost_syncpt.h b/drivers/video/tegra/host/nvhost_syncpt.h
index b71cb3e6287e..9ee4f3a8d49d 100644
--- a/drivers/video/tegra/host/nvhost_syncpt.h
+++ b/drivers/video/tegra/host/nvhost_syncpt.h
@@ -24,15 +24,10 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/nvhost.h>
-#include <mach/nvmap.h>
#include <linux/atomic.h>
-struct nvhost_syncpt;
-struct nvhost_waitchk;
-
/* host managed and invalid syncpt id */
#define NVSYNCPT_GRAPHICS_HOST (0)
-#define NVSYNCPT_INVALID (-1)
/* Attribute struct for sysfs min and max attributes */
struct nvhost_syncpt_attr {
@@ -46,22 +41,17 @@ struct nvhost_syncpt {
atomic_t *min_val;
atomic_t *max_val;
u32 *base_val;
- u32 nb_pts;
- u32 nb_bases;
- u32 client_managed;
atomic_t *lock_counts;
- u32 nb_mlocks;
+ const char **syncpt_names;
struct nvhost_syncpt_attr *syncpt_attrs;
};
int nvhost_syncpt_init(struct nvhost_device *, struct nvhost_syncpt *);
void nvhost_syncpt_deinit(struct nvhost_syncpt *);
-#define client_managed(id) (BIT(id) & sp->client_managed)
#define syncpt_to_dev(sp) container_of(sp, struct nvhost_master, syncpt)
-#define syncpt_op(sp) (syncpt_to_dev(sp)->op.syncpt)
-#define SYNCPT_CHECK_PERIOD (2*HZ)
-
+#define SYNCPT_CHECK_PERIOD (2 * HZ)
+#define MAX_STUCK_CHECK_COUNT 15
/**
* Updates the value sent to hardware.
@@ -95,11 +85,16 @@ static inline u32 nvhost_syncpt_read_min(struct nvhost_syncpt *sp, u32 id)
return (u32)atomic_read(&sp->min_val[id]);
}
+int nvhost_syncpt_client_managed(struct nvhost_syncpt *sp, u32 id);
+int nvhost_syncpt_nb_pts(struct nvhost_syncpt *sp);
+int nvhost_syncpt_nb_bases(struct nvhost_syncpt *sp);
+int nvhost_syncpt_nb_mlocks(struct nvhost_syncpt *sp);
+
static inline bool nvhost_syncpt_check_max(struct nvhost_syncpt *sp,
u32 id, u32 real)
{
u32 max;
- if (client_managed(id))
+ if (nvhost_syncpt_client_managed(sp, id))
return true;
max = nvhost_syncpt_read_max(sp, id);
return (s32)(max - real) >= 0;
@@ -140,25 +135,15 @@ static inline int nvhost_syncpt_wait(struct nvhost_syncpt *sp, u32 id, u32 thres
MAX_SCHEDULE_TIMEOUT, NULL);
}
-/*
- * Check driver supplied waitchk structs for syncpt thresholds
- * that have already been satisfied and NULL the comparison (to
- * avoid a wrap condition in the HW).
- *
- * @param: sp - global shadowed syncpt struct
- * @param: nvmap - needed to access command buffer
- * @param: mask - bit mask of syncpt IDs referenced in WAITs
- * @param: wait - start of filled in array of waitchk structs
- * @param: waitend - end ptr (one beyond last valid waitchk)
- */
-int nvhost_syncpt_wait_check(struct nvhost_syncpt *sp,
- struct nvmap_client *nvmap,
- u32 mask,
- struct nvhost_waitchk *wait,
- int num_waitchk);
+int nvhost_syncpt_patch_wait(struct nvhost_syncpt *sp, void *patch_addr);
void nvhost_syncpt_debug(struct nvhost_syncpt *sp);
+static inline int nvhost_syncpt_is_valid(struct nvhost_syncpt *sp, u32 id)
+{
+ return id != NVSYNCPT_INVALID && id < nvhost_syncpt_nb_pts(sp);
+}
+
int nvhost_mutex_try_lock(struct nvhost_syncpt *sp, int idx);
void nvhost_mutex_unlock(struct nvhost_syncpt *sp, int idx);
diff --git a/drivers/video/tegra/host/nvmap.c b/drivers/video/tegra/host/nvmap.c
new file mode 100644
index 000000000000..fd82f40c59ff
--- /dev/null
+++ b/drivers/video/tegra/host/nvmap.c
@@ -0,0 +1,100 @@
+/*
+ * drivers/video/tegra/host/nvmap.c
+ *
+ * Tegra Graphics Host Nvmap support
+ *
+ * Copyright (c) 2012, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "chip_support.h"
+#include <linux/nvmap.h>
+
+struct mem_mgr *nvhost_nvmap_alloc_mgr(void)
+{
+ return (struct mem_mgr *)nvmap_create_client(nvmap_dev, "nvhost");
+}
+
+void nvhost_nvmap_put_mgr(struct mem_mgr *mgr)
+{
+ nvmap_client_put((struct nvmap_client *)mgr);
+}
+
+struct mem_mgr *nvhost_nvmap_get_mgr(struct mem_mgr *mgr)
+{
+ return (struct mem_mgr *)nvmap_client_get((struct nvmap_client *)mgr);
+}
+
+struct mem_mgr *nvhost_nvmap_get_mgr_file(int fd)
+{
+ return (struct mem_mgr *)nvmap_client_get_file(fd);
+}
+
+struct mem_handle *nvhost_nvmap_alloc(struct mem_mgr *mgr,
+ size_t size, size_t align, int flags)
+{
+ return (struct mem_handle *)nvmap_alloc((struct nvmap_client *)mgr,
+ size, align, flags, 0);
+}
+
+void nvhost_nvmap_put(struct mem_mgr *mgr, struct mem_handle *handle)
+{
+ return nvmap_free((struct nvmap_client *)mgr,
+ (struct nvmap_handle_ref *)handle);
+}
+
+phys_addr_t nvhost_nvmap_pin(struct mem_mgr *mgr, struct mem_handle *handle)
+{
+ return nvmap_pin((struct nvmap_client *)mgr,
+ (struct nvmap_handle_ref *)handle);
+}
+
+void nvhost_nvmap_unpin(struct mem_mgr *mgr, struct mem_handle *handle)
+{
+ return nvmap_unpin((struct nvmap_client *)mgr,
+ (struct nvmap_handle_ref *)handle);
+}
+
+void *nvhost_nvmap_mmap(struct mem_handle *handle)
+{
+ return nvmap_mmap((struct nvmap_handle_ref *)handle);
+}
+
+void nvhost_nvmap_munmap(struct mem_handle *handle, void *addr)
+{
+ nvmap_munmap((struct nvmap_handle_ref *)handle, addr);
+}
+
+struct mem_handle *nvhost_nvmap_get(struct mem_mgr *mgr, u32 id)
+{
+ return (struct mem_handle *)
+ nvmap_duplicate_handle_id((struct nvmap_client *)mgr, id);
+}
+
+int nvhost_init_nvmap_support(struct nvhost_chip_support *chip)
+{
+ chip->mem.alloc_mgr = nvhost_nvmap_alloc_mgr;
+ chip->mem.put_mgr = nvhost_nvmap_put_mgr;
+ chip->mem.get_mgr = nvhost_nvmap_get_mgr;
+ chip->mem.get_mgr_file = nvhost_nvmap_get_mgr_file;
+ chip->mem.alloc = nvhost_nvmap_alloc;
+ chip->mem.put = nvhost_nvmap_put;
+ chip->mem.get = nvhost_nvmap_get;
+ chip->mem.pin = nvhost_nvmap_pin;
+ chip->mem.unpin = nvhost_nvmap_unpin;
+ chip->mem.mmap = nvhost_nvmap_mmap;
+ chip->mem.munmap = nvhost_nvmap_munmap;
+
+ return 0;
+}
diff --git a/drivers/video/tegra/host/nvmap.h b/drivers/video/tegra/host/nvmap.h
new file mode 100644
index 000000000000..90f64d44f434
--- /dev/null
+++ b/drivers/video/tegra/host/nvmap.h
@@ -0,0 +1,27 @@
+/*
+ * drivers/video/tegra/host/nvmap.h
+ *
+ * Tegra Graphics Host nvmap memory manager
+ *
+ * Copyright (c) 2010-2012, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __NVHOST_NVMAP_H
+#define __NVHOST_NVMAP_H
+
+struct nvhost_chip_support;
+int nvhost_init_nvmap_support(struct nvhost_chip_support *op);
+
+#endif
diff --git a/drivers/video/tegra/host/t20/t20.c b/drivers/video/tegra/host/t20/t20.c
index 24ddedc842e4..71ed7334e714 100644
--- a/drivers/video/tegra/host/t20/t20.c
+++ b/drivers/video/tegra/host/t20/t20.c
@@ -18,18 +18,18 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <linux/slab.h>
+#include <linux/nvhost_ioctl.h>
#include <mach/powergate.h>
-#include "dev.h"
+#include <mach/iomap.h>
#include "t20.h"
-#include "host1x/host1x_channel.h"
-#include "host1x/host1x_syncpt.h"
-#include "host1x/host1x_hardware.h"
-#include "host1x/host1x_cdma.h"
-#include "gr3d/gr3d.h"
#include "gr3d/gr3d_t20.h"
#include "mpe/mpe.h"
-#include "nvhost_hwctx.h"
+#include "host1x/host1x.h"
+#include "nvhost_channel.h"
+#include "nvhost_memmgr.h"
+#include "host1x/host1x01_hardware.h"
+#include "host1x/host1x_syncpt.h"
+#include "chip_support.h"
#define NVMODMUTEX_2D_FULL (1)
#define NVMODMUTEX_2D_SIMPLE (2)
@@ -41,15 +41,67 @@
#define NVMODMUTEX_VI (8)
#define NVMODMUTEX_DSI (9)
-#define NVHOST_NUMCHANNELS (NV_HOST1X_CHANNELS - 1)
+static int t20_num_alloc_channels = 0;
-struct nvhost_device t20_devices[] = {
-{
- /* channel 0 */
+static struct resource tegra_host1x01_resources[] = {
+ {
+ .start = TEGRA_HOST1X_BASE,
+ .end = TEGRA_HOST1X_BASE + TEGRA_HOST1X_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = INT_SYNCPT_THRESH_BASE,
+ .end = INT_SYNCPT_THRESH_BASE + INT_SYNCPT_THRESH_NR - 1,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = INT_HOST1X_MPCORE_GENERAL,
+ .end = INT_HOST1X_MPCORE_GENERAL,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static const char *s_syncpt_names[32] = {
+ "gfx_host",
+ "", "", "", "", "", "", "",
+ "disp0_a", "disp1_a", "avp_0",
+ "csi_vi_0", "csi_vi_1",
+ "vi_isp_0", "vi_isp_1", "vi_isp_2", "vi_isp_3", "vi_isp_4",
+ "2d_0", "2d_1",
+ "disp0_b", "disp1_b",
+ "3d",
+ "mpe",
+ "disp0_c", "disp1_c",
+ "vblank0", "vblank1",
+ "mpe_ebm_eof", "mpe_wr_safe",
+ "2d_tinyblt",
+ "dsi"
+};
+
+static struct host1x_device_info host1x01_info = {
+ .nb_channels = 8,
+ .nb_pts = 32,
+ .nb_mlocks = 16,
+ .nb_bases = 8,
+ .syncpt_names = s_syncpt_names,
+ .client_managed = NVSYNCPTS_CLIENT_MANAGED,
+};
+
+static struct nvhost_device tegra_host1x01_device = {
+ .dev = {.platform_data = &host1x01_info},
+ .name = "host1x",
+ .id = -1,
+ .resource = tegra_host1x01_resources,
+ .num_resources = ARRAY_SIZE(tegra_host1x01_resources),
+ .clocks = {{"host1x", UINT_MAX}, {} },
+ NVHOST_MODULE_NO_POWERGATE_IDS,
+};
+
+static struct nvhost_device tegra_display01_device = {
.name = "display",
.id = -1,
.index = 0,
- .syncpts = BIT(NVSYNCPT_DISP0_A) | BIT(NVSYNCPT_DISP1_A) |
+ .syncpts = BIT(NVSYNCPT_DISP0_A) | BIT(NVSYNCPT_DISP1_A) |
BIT(NVSYNCPT_DISP0_B) | BIT(NVSYNCPT_DISP1_B) |
BIT(NVSYNCPT_DISP0_C) | BIT(NVSYNCPT_DISP1_C) |
BIT(NVSYNCPT_VBLANK0) | BIT(NVSYNCPT_VBLANK1),
@@ -57,25 +109,24 @@ struct nvhost_device t20_devices[] = {
NVHOST_MODULE_NO_POWERGATE_IDS,
NVHOST_DEFAULT_CLOCKGATE_DELAY,
.moduleid = NVHOST_MODULE_NONE,
-},
-{
- /* channel 1 */
+};
+
+static struct nvhost_device tegra_gr3d01_device = {
.name = "gr3d",
+ .version = 1,
.id = -1,
.index = 1,
.syncpts = BIT(NVSYNCPT_3D),
.waitbases = BIT(NVWAITBASE_3D),
.modulemutexes = BIT(NVMODMUTEX_3D),
.class = NV_GRAPHICS_3D_CLASS_ID,
- .prepare_poweroff = nvhost_gr3d_prepare_power_off,
- .alloc_hwctx_handler = nvhost_gr3d_t20_ctxhandler_init,
- .clocks = {{"gr3d", UINT_MAX}, {"emc", UINT_MAX}, {} },
+ .clocks = {{"gr3d", UINT_MAX}, {"emc", UINT_MAX}, {} },
.powergate_ids = {TEGRA_POWERGATE_3D, -1},
NVHOST_DEFAULT_CLOCKGATE_DELAY,
.moduleid = NVHOST_MODULE_NONE,
-},
-{
- /* channel 2 */
+};
+
+static struct nvhost_device tegra_gr2d01_device = {
.name = "gr2d",
.id = -1,
.index = 2,
@@ -83,26 +134,49 @@ struct nvhost_device t20_devices[] = {
.waitbases = BIT(NVWAITBASE_2D_0) | BIT(NVWAITBASE_2D_1),
.modulemutexes = BIT(NVMODMUTEX_2D_FULL) | BIT(NVMODMUTEX_2D_SIMPLE) |
BIT(NVMODMUTEX_2D_SB_A) | BIT(NVMODMUTEX_2D_SB_B),
- .clocks = { {"gr2d", UINT_MAX},
+ .clocks = { {"gr2d", UINT_MAX},
{"epp", UINT_MAX},
{"emc", UINT_MAX} },
NVHOST_MODULE_NO_POWERGATE_IDS,
.clockgate_delay = 0,
.moduleid = NVHOST_MODULE_NONE,
-},
-{
- /* channel 3 */
+ .serialize = true,
+};
+
+static struct resource isp_resources_t20[] = {
+ {
+ .name = "regs",
+ .start = TEGRA_ISP_BASE,
+ .end = TEGRA_ISP_BASE + TEGRA_ISP_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct nvhost_device tegra_isp01_device = {
.name = "isp",
.id = -1,
+ .resource = isp_resources_t20,
+ .num_resources = ARRAY_SIZE(isp_resources_t20),
.index = 3,
.syncpts = 0,
NVHOST_MODULE_NO_POWERGATE_IDS,
NVHOST_DEFAULT_CLOCKGATE_DELAY,
.moduleid = NVHOST_MODULE_ISP,
-},
-{
- /* channel 4 */
+};
+
+static struct resource vi_resources[] = {
+ {
+ .name = "regs",
+ .start = TEGRA_VI_BASE,
+ .end = TEGRA_VI_BASE + TEGRA_VI_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct nvhost_device tegra_vi01_device = {
.name = "vi",
+ .resource = vi_resources,
+ .num_resources = ARRAY_SIZE(vi_resources),
.id = -1,
.index = 4,
.syncpts = BIT(NVSYNCPT_CSI_VI_0) | BIT(NVSYNCPT_CSI_VI_1) |
@@ -114,11 +188,23 @@ struct nvhost_device t20_devices[] = {
NVHOST_MODULE_NO_POWERGATE_IDS,
NVHOST_DEFAULT_CLOCKGATE_DELAY,
.moduleid = NVHOST_MODULE_VI,
-},
-{
- /* channel 5 */
+};
+
+static struct resource tegra_mpe01_resources[] = {
+ {
+ .name = "regs",
+ .start = TEGRA_MPE_BASE,
+ .end = TEGRA_MPE_BASE + TEGRA_MPE_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct nvhost_device tegra_mpe01_device = {
.name = "mpe",
+ .version = 1,
.id = -1,
+ .resource = tegra_mpe01_resources,
+ .num_resources = ARRAY_SIZE(tegra_mpe01_resources),
.index = 5,
.syncpts = BIT(NVSYNCPT_MPE) | BIT(NVSYNCPT_MPE_EBM_EOF) |
BIT(NVSYNCPT_MPE_WR_SAFE),
@@ -126,16 +212,14 @@ struct nvhost_device t20_devices[] = {
.class = NV_VIDEO_ENCODE_MPEG_CLASS_ID,
.waitbasesync = true,
.keepalive = true,
- .prepare_poweroff = nvhost_mpe_prepare_power_off,
- .alloc_hwctx_handler = nvhost_mpe_ctxhandler_init,
.clocks = { {"mpe", UINT_MAX},
{"emc", UINT_MAX} },
.powergate_ids = {TEGRA_POWERGATE_MPE, -1},
NVHOST_DEFAULT_CLOCKGATE_DELAY,
.moduleid = NVHOST_MODULE_MPE,
-},
-{
- /* channel 6 */
+};
+
+static struct nvhost_device tegra_dsi01_device = {
.name = "dsi",
.id = -1,
.index = 6,
@@ -144,90 +228,61 @@ struct nvhost_device t20_devices[] = {
NVHOST_MODULE_NO_POWERGATE_IDS,
NVHOST_DEFAULT_CLOCKGATE_DELAY,
.moduleid = NVHOST_MODULE_NONE,
-} };
+};
+static struct nvhost_device *t20_devices[] = {
+ &tegra_host1x01_device,
+ &tegra_display01_device,
+ &tegra_gr3d01_device,
+ &tegra_gr2d01_device,
+ &tegra_isp01_device,
+ &tegra_vi01_device,
+ &tegra_mpe01_device,
+ &tegra_dsi01_device,
+};
-static inline void __iomem *t20_channel_aperture(void __iomem *p, int ndx)
+int tegra2_register_host1x_devices(void)
{
- p += NV_HOST1X_CHANNEL0_BASE;
- p += ndx * NV_HOST1X_CHANNEL_MAP_SIZE_BYTES;
- return p;
+ return nvhost_add_devices(t20_devices, ARRAY_SIZE(t20_devices));
}
-static inline int t20_nvhost_hwctx_handler_init(struct nvhost_channel *ch)
+static void t20_free_nvhost_channel(struct nvhost_channel *ch)
{
- int err = 0;
- unsigned long syncpts = ch->dev->syncpts;
- unsigned long waitbases = ch->dev->waitbases;
- u32 syncpt = find_first_bit(&syncpts, BITS_PER_LONG);
- u32 waitbase = find_first_bit(&waitbases, BITS_PER_LONG);
-
- if (ch->dev->alloc_hwctx_handler) {
- ch->ctxhandler = ch->dev->alloc_hwctx_handler(syncpt,
- waitbase, ch);
- if (!ch->ctxhandler)
- err = -ENOMEM;
- }
-
- return err;
+ nvhost_free_channel_internal(ch, &t20_num_alloc_channels);
}
-static int t20_channel_init(struct nvhost_channel *ch,
- struct nvhost_master *dev, int index)
+static struct nvhost_channel *t20_alloc_nvhost_channel(
+ struct nvhost_device *dev)
{
- ch->chid = index;
- mutex_init(&ch->reflock);
- mutex_init(&ch->submitlock);
-
- ch->aperture = t20_channel_aperture(dev->aperture, index);
-
- return t20_nvhost_hwctx_handler_init(ch);
+ return nvhost_alloc_channel_internal(dev->index,
+ nvhost_get_host(dev)->info.nb_channels,
+ &t20_num_alloc_channels);
}
-int nvhost_init_t20_channel_support(struct nvhost_master *host)
-{
- host->nb_channels = NVHOST_NUMCHANNELS;
-
- host->op.channel.init = t20_channel_init;
- host->op.channel.submit = host1x_channel_submit;
- host->op.channel.read3dreg = host1x_channel_read_3d_reg;
+#include "host1x/host1x_channel.c"
+#include "host1x/host1x_cdma.c"
+#include "host1x/host1x_debug.c"
+#include "host1x/host1x_syncpt.c"
+#include "host1x/host1x_intr.c"
- return 0;
-}
-
-struct nvhost_device *t20_get_nvhost_device(struct nvhost_master *host,
- char *name)
-{
- int i;
-
- for (i = 0; i < host->nb_channels; i++) {
- if (strcmp(t20_devices[i].name, name) == 0)
- return &t20_devices[i];
- }
-
- return NULL;
-}
-
-int nvhost_init_t20_support(struct nvhost_master *host)
+int nvhost_init_t20_support(struct nvhost_master *host,
+ struct nvhost_chip_support *op)
{
int err;
- /* don't worry about cleaning up on failure... "remove" does it. */
- err = nvhost_init_t20_channel_support(host);
- if (err)
- return err;
- err = host1x_init_cdma_support(host);
- if (err)
- return err;
- err = nvhost_init_t20_debug_support(host);
+ op->channel = host1x_channel_ops;
+ op->cdma = host1x_cdma_ops;
+ op->push_buffer = host1x_pushbuffer_ops;
+ op->debug = host1x_debug_ops;
+ host->sync_aperture = host->aperture + HOST1X_CHANNEL_SYNC_REG_BASE;
+ op->syncpt = host1x_syncpt_ops;
+ op->intr = host1x_intr_ops;
+ err = nvhost_memmgr_init(op);
if (err)
return err;
- err = host1x_init_syncpt_support(host);
- if (err)
- return err;
- err = nvhost_init_t20_intr_support(host);
- if (err)
- return err;
- host->op.nvhost_dev.get_nvhost_device = t20_get_nvhost_device;
+
+ op->nvhost_dev.alloc_nvhost_channel = t20_alloc_nvhost_channel;
+ op->nvhost_dev.free_nvhost_channel = t20_free_nvhost_channel;
+
return 0;
}
diff --git a/drivers/video/tegra/host/t20/t20.h b/drivers/video/tegra/host/t20/t20.h
index 93555a55b589..729f9d8e85e4 100644
--- a/drivers/video/tegra/host/t20/t20.h
+++ b/drivers/video/tegra/host/t20/t20.h
@@ -21,13 +21,9 @@
#define _NVHOST_T20_H_
struct nvhost_master;
-struct nvhost_module;
+struct nvhost_chip_support;
-int nvhost_init_t20_channel_support(struct nvhost_master *);
-int nvhost_init_t20_debug_support(struct nvhost_master *);
-int nvhost_init_t20_syncpt_support(struct nvhost_master *);
-int nvhost_init_t20_intr_support(struct nvhost_master *);
-int nvhost_init_t20_support(struct nvhost_master *host);
-int nvhost_t20_save_context(struct nvhost_module *mod, u32 syncpt_id);
+int nvhost_init_t20_support(struct nvhost_master *,
+ struct nvhost_chip_support *);
#endif /* _NVHOST_T20_H_ */
diff --git a/drivers/video/tegra/host/t30/t30.c b/drivers/video/tegra/host/t30/t30.c
index fb69d4e0f57a..0c8d626a4d67 100644
--- a/drivers/video/tegra/host/t30/t30.c
+++ b/drivers/video/tegra/host/t30/t30.c
@@ -18,20 +18,20 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <linux/mutex.h>
+#include <linux/nvhost_ioctl.h>
#include <mach/powergate.h>
#include <mach/iomap.h>
-#include "dev.h"
#include "t20/t20.h"
#include "t30.h"
-#include "gr3d/gr3d.h"
-#include "mpe/mpe.h"
#include "gr3d/gr3d_t30.h"
#include "gr3d/scale3d.h"
-#include "host1x/host1x_hardware.h"
-#include "host1x/host1x_cdma.h"
-#include "host1x/host1x_syncpt.h"
+#include "mpe/mpe.h"
+#include "host1x/host1x.h"
+#include "host1x/host1x01_hardware.h"
#include "chip_support.h"
+#include "nvhost_channel.h"
+#include "nvhost_memmgr.h"
+#include "host1x/host1x_syncpt.h"
#define NVMODMUTEX_2D_FULL (1)
#define NVMODMUTEX_2D_SIMPLE (2)
@@ -43,15 +43,67 @@
#define NVMODMUTEX_VI (8)
#define NVMODMUTEX_DSI (9)
-#define NVHOST_CHANNEL_BASE 0
+static int t30_num_alloc_channels = 0;
-struct nvhost_device t30_devices[] = {
-{
- /* channel 0 */
+static struct resource tegra_host1x01_resources[] = {
+ {
+ .start = TEGRA_HOST1X_BASE,
+ .end = TEGRA_HOST1X_BASE + TEGRA_HOST1X_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = INT_SYNCPT_THRESH_BASE,
+ .end = INT_SYNCPT_THRESH_BASE + INT_SYNCPT_THRESH_NR - 1,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = INT_HOST1X_MPCORE_GENERAL,
+ .end = INT_HOST1X_MPCORE_GENERAL,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static const char *s_syncpt_names[32] = {
+ "gfx_host",
+ "", "", "", "", "", "", "",
+ "disp0_a", "disp1_a", "avp_0",
+ "csi_vi_0", "csi_vi_1",
+ "vi_isp_0", "vi_isp_1", "vi_isp_2", "vi_isp_3", "vi_isp_4",
+ "2d_0", "2d_1",
+ "disp0_b", "disp1_b",
+ "3d",
+ "mpe",
+ "disp0_c", "disp1_c",
+ "vblank0", "vblank1",
+ "mpe_ebm_eof", "mpe_wr_safe",
+ "2d_tinyblt",
+ "dsi"
+};
+
+static struct host1x_device_info host1x01_info = {
+ .nb_channels = 8,
+ .nb_pts = 32,
+ .nb_mlocks = 16,
+ .nb_bases = 8,
+ .syncpt_names = s_syncpt_names,
+ .client_managed = NVSYNCPTS_CLIENT_MANAGED,
+};
+
+static struct nvhost_device tegra_host1x01_device = {
+ .dev = {.platform_data = &host1x01_info},
+ .name = "host1x",
+ .id = -1,
+ .resource = tegra_host1x01_resources,
+ .num_resources = ARRAY_SIZE(tegra_host1x01_resources),
+ .clocks = {{"host1x", UINT_MAX}, {} },
+ NVHOST_MODULE_NO_POWERGATE_IDS,
+};
+
+static struct nvhost_device tegra_display01_device = {
.name = "display",
.id = -1,
.index = 0,
- .syncpts = BIT(NVSYNCPT_DISP0_A) | BIT(NVSYNCPT_DISP1_A) |
+ .syncpts = BIT(NVSYNCPT_DISP0_A) | BIT(NVSYNCPT_DISP1_A) |
BIT(NVSYNCPT_DISP0_B) | BIT(NVSYNCPT_DISP1_B) |
BIT(NVSYNCPT_DISP0_C) | BIT(NVSYNCPT_DISP1_C) |
BIT(NVSYNCPT_VBLANK0) | BIT(NVSYNCPT_VBLANK1),
@@ -59,23 +111,17 @@ struct nvhost_device t30_devices[] = {
NVHOST_MODULE_NO_POWERGATE_IDS,
NVHOST_DEFAULT_CLOCKGATE_DELAY,
.moduleid = NVHOST_MODULE_NONE,
-},
-{
- /* channel 1 */
+};
+
+static struct nvhost_device tegra_gr3d02_device = {
.name = "gr3d",
+ .version = 2,
.id = -1,
.index = 1,
- .syncpts = BIT(NVSYNCPT_3D),
+ .syncpts = BIT(NVSYNCPT_3D),
.waitbases = BIT(NVWAITBASE_3D),
.modulemutexes = BIT(NVMODMUTEX_3D),
.class = NV_GRAPHICS_3D_CLASS_ID,
- .prepare_poweroff = nvhost_gr3d_prepare_power_off,
- .busy = nvhost_scale3d_notify_busy,
- .idle = nvhost_scale3d_notify_idle,
- .init = nvhost_scale3d_init,
- .deinit = nvhost_scale3d_deinit,
- .suspend = nvhost_scale3d_suspend,
- .alloc_hwctx_handler = nvhost_gr3d_t30_ctxhandler_init,
.clocks = { {"gr3d", UINT_MAX},
{"gr3d2", UINT_MAX},
{"emc", UINT_MAX} },
@@ -86,9 +132,9 @@ struct nvhost_device t30_devices[] = {
.powerup_reset = true,
.powergate_delay = 250,
.moduleid = NVHOST_MODULE_NONE,
-},
-{
- /* channel 2 */
+};
+
+static struct nvhost_device tegra_gr2d02_device = {
.name = "gr2d",
.id = -1,
.index = 2,
@@ -96,29 +142,56 @@ struct nvhost_device t30_devices[] = {
.waitbases = BIT(NVWAITBASE_2D_0) | BIT(NVWAITBASE_2D_1),
.modulemutexes = BIT(NVMODMUTEX_2D_FULL) | BIT(NVMODMUTEX_2D_SIMPLE) |
BIT(NVMODMUTEX_2D_SB_A) | BIT(NVMODMUTEX_2D_SB_B),
- .clocks = { {"gr2d", UINT_MAX},
- {"epp", 0},
- {"emc", 300000000} },
+ .clocks = { {"gr2d", UINT_MAX},
+ {"epp", 0},
+ {"emc", 300000000} },
NVHOST_MODULE_NO_POWERGATE_IDS,
.clockgate_delay = 0,
.moduleid = NVHOST_MODULE_NONE,
-},
-{
- /* channel 3 */
+ .serialize = true,
+};
+
+static struct resource isp_resources_t20[] = {
+ {
+ .name = "regs",
+ .start = TEGRA_ISP_BASE,
+ .end = TEGRA_ISP_BASE + TEGRA_ISP_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct nvhost_device tegra_isp01_device = {
.name = "isp",
.id = -1,
+ .resource = isp_resources_t20,
+ .num_resources = ARRAY_SIZE(isp_resources_t20),
.index = 3,
- .syncpts = 0,
+ .syncpts = BIT(NVSYNCPT_VI_ISP_2) | BIT(NVSYNCPT_VI_ISP_3) |
+ BIT(NVSYNCPT_VI_ISP_4),
+ .clocks = { {"epp", 0}
+ },
+ .keepalive = true,
NVHOST_MODULE_NO_POWERGATE_IDS,
NVHOST_DEFAULT_CLOCKGATE_DELAY,
.moduleid = NVHOST_MODULE_ISP,
-},
-{
- /* channel 4 */
+};
+
+static struct resource vi_resources[] = {
+ {
+ .name = "regs",
+ .start = TEGRA_VI_BASE,
+ .end = TEGRA_VI_BASE + TEGRA_VI_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct nvhost_device tegra_vi01_device = {
.name = "vi",
+ .resource = vi_resources,
+ .num_resources = ARRAY_SIZE(vi_resources),
.id = -1,
.index = 4,
- .syncpts = BIT(NVSYNCPT_CSI_VI_0) | BIT(NVSYNCPT_CSI_VI_1) |
+ .syncpts = BIT(NVSYNCPT_CSI_VI_0) | BIT(NVSYNCPT_CSI_VI_1) |
BIT(NVSYNCPT_VI_ISP_0) | BIT(NVSYNCPT_VI_ISP_1) |
BIT(NVSYNCPT_VI_ISP_2) | BIT(NVSYNCPT_VI_ISP_3) |
BIT(NVSYNCPT_VI_ISP_4),
@@ -127,11 +200,23 @@ struct nvhost_device t30_devices[] = {
NVHOST_MODULE_NO_POWERGATE_IDS,
NVHOST_DEFAULT_CLOCKGATE_DELAY,
.moduleid = NVHOST_MODULE_VI,
-},
-{
- /* channel 5 */
+};
+
+static struct resource tegra_mpe01_resources[] = {
+ {
+ .name = "regs",
+ .start = TEGRA_MPE_BASE,
+ .end = TEGRA_MPE_BASE + TEGRA_MPE_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct nvhost_device tegra_mpe02_device = {
.name = "mpe",
+ .version = 2,
.id = -1,
+ .resource = tegra_mpe01_resources,
+ .num_resources = ARRAY_SIZE(tegra_mpe01_resources),
.index = 5,
.syncpts = BIT(NVSYNCPT_MPE) | BIT(NVSYNCPT_MPE_EBM_EOF) |
BIT(NVSYNCPT_MPE_WR_SAFE),
@@ -139,18 +224,16 @@ struct nvhost_device t30_devices[] = {
.class = NV_VIDEO_ENCODE_MPEG_CLASS_ID,
.waitbasesync = true,
.keepalive = true,
- .prepare_poweroff = nvhost_mpe_prepare_power_off,
- .alloc_hwctx_handler = nvhost_mpe_ctxhandler_init,
- .clocks = { {"mpe", UINT_MAX},
+ .clocks = { {"mpe", UINT_MAX},
{"emc", UINT_MAX} },
.powergate_ids = {TEGRA_POWERGATE_MPE, -1},
NVHOST_DEFAULT_CLOCKGATE_DELAY,
.can_powergate = true,
.powergate_delay = 100,
.moduleid = NVHOST_MODULE_MPE,
-},
-{
- /* channel 6 */
+};
+
+static struct nvhost_device tegra_dsi01_device = {
.name = "dsi",
.id = -1,
.index = 6,
@@ -159,94 +242,62 @@ struct nvhost_device t30_devices[] = {
NVHOST_MODULE_NO_POWERGATE_IDS,
NVHOST_DEFAULT_CLOCKGATE_DELAY,
.moduleid = NVHOST_MODULE_NONE,
-} };
+};
-static inline int t30_nvhost_hwctx_handler_init(struct nvhost_channel *ch)
-{
- int err = 0;
- unsigned long syncpts = ch->dev->syncpts;
- unsigned long waitbases = ch->dev->waitbases;
- u32 syncpt = find_first_bit(&syncpts, BITS_PER_LONG);
- u32 waitbase = find_first_bit(&waitbases, BITS_PER_LONG);
-
- if (ch->dev->alloc_hwctx_handler) {
- ch->ctxhandler = ch->dev->alloc_hwctx_handler(syncpt,
- waitbase, ch);
- if (!ch->ctxhandler)
- err = -ENOMEM;
- }
+static struct nvhost_device *t30_devices[] = {
+ &tegra_host1x01_device,
+ &tegra_display01_device,
+ &tegra_gr3d02_device,
+ &tegra_gr2d02_device,
+ &tegra_isp01_device,
+ &tegra_vi01_device,
+ &tegra_mpe02_device,
+ &tegra_dsi01_device,
+};
- return err;
-}
-
-static inline void __iomem *t30_channel_aperture(void __iomem *p, int ndx)
+int tegra3_register_host1x_devices(void)
{
- ndx += NVHOST_CHANNEL_BASE;
- p += NV_HOST1X_CHANNEL0_BASE;
- p += ndx * NV_HOST1X_CHANNEL_MAP_SIZE_BYTES;
- return p;
+ return nvhost_add_devices(t30_devices, ARRAY_SIZE(t30_devices));
}
-static int t30_channel_init(struct nvhost_channel *ch,
- struct nvhost_master *dev, int index)
+static void t30_free_nvhost_channel(struct nvhost_channel *ch)
{
- ch->chid = index;
- mutex_init(&ch->reflock);
- mutex_init(&ch->submitlock);
-
- ch->aperture = t30_channel_aperture(dev->aperture, index);
-
- return t30_nvhost_hwctx_handler_init(ch);
+ nvhost_free_channel_internal(ch, &t30_num_alloc_channels);
}
-int nvhost_init_t30_channel_support(struct nvhost_master *host)
+static struct nvhost_channel *t30_alloc_nvhost_channel(
+ struct nvhost_device *dev)
{
- int result = nvhost_init_t20_channel_support(host);
- host->op.channel.init = t30_channel_init;
-
- return result;
+ return nvhost_alloc_channel_internal(dev->index,
+ nvhost_get_host(dev)->info.nb_channels,
+ &t30_num_alloc_channels);
}
-int nvhost_init_t30_debug_support(struct nvhost_master *host)
-{
- nvhost_init_t20_debug_support(host);
- host->op.debug.debug_init = nvhost_scale3d_debug_init;
- return 0;
-}
+#include "host1x/host1x_channel.c"
+#include "host1x/host1x_cdma.c"
+#include "host1x/host1x_debug.c"
+#include "host1x/host1x_syncpt.c"
+#include "host1x/host1x_intr.c"
-struct nvhost_device *t30_get_nvhost_device(struct nvhost_master *host,
- char *name)
-{
- int i;
-
- for (i = 0; i < host->nb_channels; i++) {
- if (strcmp(t30_devices[i].name, name) == 0)
- return &t30_devices[i];
- }
-
- return NULL;
-}
-
-int nvhost_init_t30_support(struct nvhost_master *host)
+int nvhost_init_t30_support(struct nvhost_master *host,
+ struct nvhost_chip_support *op)
{
int err;
- /* don't worry about cleaning up on failure... "remove" does it. */
- err = nvhost_init_t30_channel_support(host);
- if (err)
- return err;
- err = host1x_init_cdma_support(host);
- if (err)
- return err;
- err = nvhost_init_t30_debug_support(host);
+ op->channel = host1x_channel_ops;
+ op->cdma = host1x_cdma_ops;
+ op->push_buffer = host1x_pushbuffer_ops;
+ op->debug = host1x_debug_ops;
+ op->debug.debug_init = nvhost_scale3d_debug_init;
+ host->sync_aperture = host->aperture + HOST1X_CHANNEL_SYNC_REG_BASE;
+ op->syncpt = host1x_syncpt_ops;
+ op->intr = host1x_intr_ops;
+ err = nvhost_memmgr_init(op);
if (err)
return err;
- err = host1x_init_syncpt_support(host);
- if (err)
- return err;
- err = nvhost_init_t20_intr_support(host);
- if (err)
- return err;
- host->op.nvhost_dev.get_nvhost_device = t30_get_nvhost_device;
+
+ op->nvhost_dev.alloc_nvhost_channel = t30_alloc_nvhost_channel;
+ op->nvhost_dev.free_nvhost_channel = t30_free_nvhost_channel;
+
return 0;
}
diff --git a/drivers/video/tegra/host/t30/t30.h b/drivers/video/tegra/host/t30/t30.h
index 0446dbd19b39..80838a5e287c 100644
--- a/drivers/video/tegra/host/t30/t30.h
+++ b/drivers/video/tegra/host/t30/t30.h
@@ -21,9 +21,9 @@
#define _NVHOST_T30_H_
struct nvhost_master;
+struct nvhost_chip_support;
-int nvhost_init_t30_channel_support(struct nvhost_master *);
-int nvhost_init_t30_debug_support(struct nvhost_master *);
-int nvhost_init_t30_support(struct nvhost_master *host);
+int nvhost_init_t30_support(struct nvhost_master *host,
+ struct nvhost_chip_support *);
#endif /* _NVHOST_T30_H_ */
diff --git a/drivers/video/tegra/host/vi/vi.c b/drivers/video/tegra/host/vi/vi.c
index a6f902a1ac7b..ee801c91efa5 100644
--- a/drivers/video/tegra/host/vi/vi.c
+++ b/drivers/video/tegra/host/vi/vi.c
@@ -18,14 +18,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <linux/resource.h>
-
-#include <mach/iomap.h>
-
#include "dev.h"
#include "bus_client.h"
-static int __devinit vi_probe(struct nvhost_device *dev)
+static int __devinit vi_probe(struct nvhost_device *dev,
+ struct nvhost_device_id *id_table)
{
int err = 0;
@@ -42,6 +39,7 @@ static int __exit vi_remove(struct nvhost_device *dev)
return 0;
}
+#ifdef CONFIG_PM
static int vi_suspend(struct nvhost_device *dev, pm_message_t state)
{
return nvhost_client_device_suspend(dev);
@@ -52,15 +50,7 @@ static int vi_resume(struct nvhost_device *dev)
dev_info(&dev->dev, "resuming\n");
return 0;
}
-
-static struct resource vi_resources = {
- .name = "regs",
- .start = TEGRA_VI_BASE,
- .end = TEGRA_VI_BASE + TEGRA_VI_SIZE - 1,
- .flags = IORESOURCE_MEM,
-};
-
-struct nvhost_device *vi_device;
+#endif
static struct nvhost_driver vi_driver = {
.probe = vi_probe,
@@ -77,18 +67,6 @@ static struct nvhost_driver vi_driver = {
static int __init vi_init(void)
{
- int err;
-
- vi_device = nvhost_get_device("vi");
- if (!vi_device)
- return -ENXIO;
-
- vi_device->resource = &vi_resources;
- vi_device->num_resources = 1;
- err = nvhost_device_register(vi_device);
- if (err)
- return err;
-
return nvhost_driver_register(&vi_driver);
}
diff --git a/drivers/video/tegra/nvmap/Makefile b/drivers/video/tegra/nvmap/Makefile
index 95d7f68836af..3da03af2b1eb 100644
--- a/drivers/video/tegra/nvmap/Makefile
+++ b/drivers/video/tegra/nvmap/Makefile
@@ -4,4 +4,5 @@ obj-y += nvmap_dev.o
obj-y += nvmap_handle.o
obj-y += nvmap_heap.o
obj-y += nvmap_ioctl.o
+obj-${CONFIG_IOMMU_API} += nvmap_iommu.o
obj-${CONFIG_NVMAP_RECLAIM_UNPINNED_VM} += nvmap_mru.o \ No newline at end of file
diff --git a/drivers/video/tegra/nvmap/nvmap.c b/drivers/video/tegra/nvmap/nvmap.c
index b4b6241618db..b7fd695d04ee 100644
--- a/drivers/video/tegra/nvmap/nvmap.c
+++ b/drivers/video/tegra/nvmap/nvmap.c
@@ -32,7 +32,7 @@
#include <asm/tlbflush.h>
#include <mach/iovmm.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include "nvmap.h"
#include "nvmap_mru.h"
@@ -352,225 +352,6 @@ static phys_addr_t handle_phys(struct nvmap_handle *h)
return addr;
}
-/* stores the physical address (+offset) of each handle relocation entry
- * into its output location. see nvmap_pin_array for more details.
- *
- * each entry in arr (i.e., each relocation request) specifies two handles:
- * the handle to pin (pin), and the handle where the address of pin should be
- * written (patch). in pseudocode, this loop basically looks like:
- *
- * for (i = 0; i < nr; i++) {
- * (pin, pin_offset, patch, patch_offset) = arr[i];
- * patch[patch_offset] = address_of(pin) + pin_offset;
- * }
- */
-static int nvmap_reloc_pin_array(struct nvmap_client *client,
- const struct nvmap_pinarray_elem *arr,
- int nr, struct nvmap_handle *gather)
-{
- struct nvmap_handle *last_patch = NULL;
- unsigned int last_pfn = 0;
- pte_t **pte;
- void *addr;
- int i;
-
- pte = nvmap_alloc_pte(client->dev, &addr);
- if (IS_ERR(pte))
- return PTR_ERR(pte);
-
- for (i = 0; i < nr; i++) {
- struct nvmap_handle *patch;
- struct nvmap_handle *pin;
- phys_addr_t reloc_addr;
- phys_addr_t phys;
- unsigned int pfn;
-
- /* all of the handles are validated and get'ted prior to
- * calling this function, so casting is safe here */
- pin = (struct nvmap_handle *)arr[i].pin_mem;
-
- if (arr[i].patch_mem == (unsigned long)last_patch) {
- patch = last_patch;
- } else if (arr[i].patch_mem == (unsigned long)gather) {
- patch = gather;
- } else {
- if (last_patch)
- nvmap_handle_put(last_patch);
-
- patch = nvmap_get_handle_id(client, arr[i].patch_mem);
- if (!patch) {
- nvmap_free_pte(client->dev, pte);
- return -EPERM;
- }
- last_patch = patch;
- }
-
- if (patch->heap_pgalloc) {
- unsigned int page = arr[i].patch_offset >> PAGE_SHIFT;
- phys = page_to_phys(patch->pgalloc.pages[page]);
- phys += (arr[i].patch_offset & ~PAGE_MASK);
- } else {
- phys = patch->carveout->base + arr[i].patch_offset;
- }
-
- pfn = __phys_to_pfn(phys);
- if (pfn != last_pfn) {
- pgprot_t prot = nvmap_pgprot(patch, pgprot_kernel);
- phys_addr_t kaddr = (phys_addr_t)addr;
- set_pte_at(&init_mm, kaddr, *pte, pfn_pte(pfn, prot));
- flush_tlb_kernel_page(kaddr);
- last_pfn = pfn;
- }
-
- reloc_addr = handle_phys(pin) + arr[i].pin_offset;
- reloc_addr >>= arr[i].reloc_shift;
- __raw_writel(reloc_addr, addr + (phys & ~PAGE_MASK));
- }
-
- nvmap_free_pte(client->dev, pte);
-
- if (last_patch)
- nvmap_handle_put(last_patch);
-
- wmb();
-
- return 0;
-}
-
-static int nvmap_validate_get_pin_array(struct nvmap_client *client,
- const struct nvmap_pinarray_elem *arr,
- int nr, struct nvmap_handle **h)
-{
- int i;
- int ret = 0;
- int count = 0;
-
- nvmap_ref_lock(client);
-
- for (i = 0; i < nr; i++) {
- struct nvmap_handle_ref *ref;
-
- if (need_resched()) {
- nvmap_ref_unlock(client);
- schedule();
- nvmap_ref_lock(client);
- }
-
- ref = _nvmap_validate_id_locked(client, arr[i].pin_mem);
-
- if (!ref)
- nvmap_warn(client, "falied to validate id\n");
- else if (!ref->handle)
- nvmap_warn(client, "id had no associated handle\n");
- else if (!ref->handle->alloc)
- nvmap_warn(client, "handle had no allocation\n");
-
- if (!ref || !ref->handle || !ref->handle->alloc) {
- ret = -EPERM;
- break;
- }
-
- /* a handle may be referenced multiple times in arr, but
- * it will only be pinned once; this ensures that the
- * minimum number of sync-queue slots in the host driver
- * are dedicated to storing unpin lists, which allows
- * for greater parallelism between the CPU and graphics
- * processor */
- if (ref->handle->flags & NVMAP_HANDLE_VISITED)
- continue;
-
- ref->handle->flags |= NVMAP_HANDLE_VISITED;
-
- h[count] = nvmap_handle_get(ref->handle);
- BUG_ON(!h[count]);
- count++;
- }
-
- nvmap_ref_unlock(client);
-
- if (ret) {
- for (i = 0; i < count; i++) {
- h[i]->flags &= ~NVMAP_HANDLE_VISITED;
- nvmap_handle_put(h[i]);
- }
- }
-
- return ret ?: count;
-}
-
-/* a typical mechanism host1x clients use for using the Tegra graphics
- * processor is to build a command buffer which contains relocatable
- * memory handle commands, and rely on the kernel to convert these in-place
- * to addresses which are understood by the GPU hardware.
- *
- * this is implemented by having clients provide a sideband array
- * of relocatable handles (+ offsets) and the location in the command
- * buffer handle to patch with the GPU address when the client submits
- * its command buffer to the host1x driver.
- *
- * the host driver also uses this relocation mechanism internally to
- * relocate the client's (unpinned) command buffers into host-addressable
- * memory.
- *
- * @client: nvmap_client which should be used for validation; should be
- * owned by the process which is submitting command buffers
- * @gather: special handle for relocated command buffer outputs used
- * internally by the host driver. if this handle is encountered
- * as an output handle in the relocation array, it is assumed
- * to be a known-good output and is not validated.
- * @arr: array of ((relocatable handle, offset), (output handle, offset))
- * tuples.
- * @nr: number of entries in arr
- * @unique_arr: list of nvmap_handle objects which were pinned by
- * nvmap_pin_array. must be unpinned by the caller after the
- * command buffers referenced in gather have completed.
- */
-int nvmap_pin_array(struct nvmap_client *client, struct nvmap_handle *gather,
- const struct nvmap_pinarray_elem *arr, int nr,
- struct nvmap_handle **unique_arr)
-{
- int count = 0;
- int ret = 0;
- int i;
-
- if (mutex_lock_interruptible(&client->share->pin_lock)) {
- nvmap_warn(client, "%s interrupted when acquiring pin lock\n",
- current->group_leader->comm);
- return -EINTR;
- }
-
- count = nvmap_validate_get_pin_array(client, arr, nr, unique_arr);
- if (count < 0) {
- mutex_unlock(&client->share->pin_lock);
- nvmap_warn(client, "failed to validate pin array\n");
- return count;
- }
-
- for (i = 0; i < count; i++)
- unique_arr[i]->flags &= ~NVMAP_HANDLE_VISITED;
-
- ret = wait_pin_array_locked(client, unique_arr, count);
-
- mutex_unlock(&client->share->pin_lock);
-
- if (!ret)
- ret = nvmap_reloc_pin_array(client, arr, nr, gather);
-
- if (WARN_ON(ret)) {
- for (i = 0; i < count; i++)
- nvmap_handle_put(unique_arr[i]);
- return ret;
- } else {
- for (i = 0; i < count; i++) {
- if (unique_arr[i]->heap_pgalloc &&
- unique_arr[i]->pgalloc.dirty)
- map_iovmm_area(unique_arr[i]);
- }
- }
-
- return count;
-}
-
phys_addr_t nvmap_pin(struct nvmap_client *client,
struct nvmap_handle_ref *ref)
{
@@ -820,52 +601,3 @@ void nvmap_free(struct nvmap_client *client, struct nvmap_handle_ref *r)
nvmap_free_handle_id(client, nvmap_ref_to_id(r));
}
-
-/*
- * create a mapping to the user's buffer and write it
- * (uses similar logic from nvmap_reloc_pin_array to map the cmdbuf)
- */
-int nvmap_patch_word(struct nvmap_client *client,
- struct nvmap_handle *patch,
- u32 patch_offset, u32 patch_value)
-{
- phys_addr_t phys;
- unsigned long kaddr;
- unsigned int pfn;
- void *addr;
- pte_t **pte;
- pgprot_t prot;
-
- if (patch_offset >= patch->size) {
- nvmap_warn(client, "read/write outside of handle\n");
- return -EFAULT;
- }
-
- pte = nvmap_alloc_pte(client->dev, &addr);
- if (IS_ERR(pte))
- return PTR_ERR(pte);
-
- /* derive physaddr of cmdbuf WAIT to patch */
- if (patch->heap_pgalloc) {
- unsigned int page = patch_offset >> PAGE_SHIFT;
- phys = page_to_phys(patch->pgalloc.pages[page]);
- phys += (patch_offset & ~PAGE_MASK);
- } else {
- phys = patch->carveout->base + patch_offset;
- }
-
- pfn = __phys_to_pfn(phys);
- prot = nvmap_pgprot(patch, pgprot_kernel);
- kaddr = (unsigned long)addr;
-
- /* write PTE, so addr points to cmdbuf PFN */
- set_pte_at(&init_mm, kaddr, *pte, pfn_pte(pfn, prot));
- flush_tlb_kernel_page(kaddr);
-
- /* write patch_value to addr + page offset */
- __raw_writel(patch_value, addr + (phys & ~PAGE_MASK));
-
- nvmap_free_pte(client->dev, pte);
- wmb();
- return 0;
-}
diff --git a/drivers/video/tegra/nvmap/nvmap.h b/drivers/video/tegra/nvmap/nvmap.h
index 44a0d86b6039..25403f5e7098 100644
--- a/drivers/video/tegra/nvmap/nvmap.h
+++ b/drivers/video/tegra/nvmap/nvmap.h
@@ -30,13 +30,15 @@
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/atomic.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include "nvmap_heap.h"
struct nvmap_device;
struct page;
struct tegra_iovmm_area;
+void _nvmap_handle_free(struct nvmap_handle *h);
+
#if defined(CONFIG_TEGRA_NVMAP)
#define nvmap_err(_client, _fmt, ...) \
dev_err(nvmap_client_to_device(_client), \
@@ -86,7 +88,7 @@ struct nvmap_handle {
struct mutex lock;
};
-#define NVMAP_DEFAULT_PAGE_POOL_SIZE 8192
+#ifdef CONFIG_NVMAP_PAGE_POOLS
#define NVMAP_UC_POOL NVMAP_HANDLE_UNCACHEABLE
#define NVMAP_WC_POOL NVMAP_HANDLE_WRITE_COMBINE
#define NVMAP_IWB_POOL NVMAP_HANDLE_INNER_CACHEABLE
@@ -103,11 +105,13 @@ struct nvmap_page_pool {
};
int nvmap_page_pool_init(struct nvmap_page_pool *pool, int flags);
+#endif
struct nvmap_share {
struct tegra_iovmm_client *iovmm;
wait_queue_head_t pin_wait;
struct mutex pin_lock;
+#ifdef CONFIG_NVMAP_PAGE_POOLS
union {
struct nvmap_page_pool pools[NVMAP_NUM_POOLS];
struct {
@@ -117,6 +121,7 @@ struct nvmap_share {
struct nvmap_page_pool wb_pool;
};
};
+#endif
#ifdef CONFIG_NVMAP_RECLAIM_UNPINNED_VM
struct mutex mru_lock;
struct list_head *mru_lists;
@@ -159,7 +164,46 @@ static inline void nvmap_ref_unlock(struct nvmap_client *priv)
{
mutex_unlock(&priv->ref_lock);
}
-#endif /* CONFIG_TEGRA_NVMAP */
+
+static inline struct nvmap_handle *nvmap_handle_get(struct nvmap_handle *h)
+{
+ if (unlikely(atomic_inc_return(&h->ref) <= 1)) {
+ pr_err("%s: %s getting a freed handle\n",
+ __func__, current->group_leader->comm);
+ if (atomic_read(&h->ref) <= 0)
+ return NULL;
+ }
+ return h;
+}
+
+static inline void nvmap_handle_put(struct nvmap_handle *h)
+{
+ int cnt = atomic_dec_return(&h->ref);
+
+ if (WARN_ON(cnt < 0)) {
+ pr_err("%s: %s put to negative references\n",
+ __func__, current->comm);
+ } else if (cnt == 0)
+ _nvmap_handle_free(h);
+}
+
+static inline pgprot_t nvmap_pgprot(struct nvmap_handle *h, pgprot_t prot)
+{
+ if (h->flags == NVMAP_HANDLE_UNCACHEABLE)
+ return pgprot_noncached(prot);
+ else if (h->flags == NVMAP_HANDLE_WRITE_COMBINE)
+ return pgprot_writecombine(prot);
+ else if (h->flags == NVMAP_HANDLE_INNER_CACHEABLE)
+ return pgprot_inner_writeback(prot);
+ return prot;
+}
+
+#else /* CONFIG_TEGRA_NVMAP */
+struct nvmap_handle *nvmap_handle_get(struct nvmap_handle *h);
+void nvmap_handle_put(struct nvmap_handle *h);
+pgprot_t nvmap_pgprot(struct nvmap_handle *h, pgprot_t prot);
+
+#endif /* !CONFIG_TEGRA_NVMAP */
struct device *nvmap_client_to_device(struct nvmap_client *client);
@@ -201,9 +245,6 @@ struct nvmap_handle *nvmap_get_handle_id(struct nvmap_client *client,
struct nvmap_handle_ref *nvmap_create_handle(struct nvmap_client *client,
size_t size);
-struct nvmap_handle_ref *nvmap_duplicate_handle_id(struct nvmap_client *client,
- unsigned long id);
-
int nvmap_alloc_handle_id(struct nvmap_client *client,
unsigned long id, unsigned int heap_mask,
size_t align, unsigned int flags);
@@ -216,51 +257,10 @@ int nvmap_pin_ids(struct nvmap_client *client,
void nvmap_unpin_ids(struct nvmap_client *priv,
unsigned int nr, const unsigned long *ids);
-void _nvmap_handle_free(struct nvmap_handle *h);
-
int nvmap_handle_remove(struct nvmap_device *dev, struct nvmap_handle *h);
void nvmap_handle_add(struct nvmap_device *dev, struct nvmap_handle *h);
-#if defined(CONFIG_TEGRA_NVMAP)
-static inline struct nvmap_handle *nvmap_handle_get(struct nvmap_handle *h)
-{
- if (unlikely(atomic_inc_return(&h->ref) <= 1)) {
- pr_err("%s: %s getting a freed handle\n",
- __func__, current->group_leader->comm);
- if (atomic_read(&h->ref) <= 0)
- return NULL;
- }
- return h;
-}
-
-static inline void nvmap_handle_put(struct nvmap_handle *h)
-{
- int cnt = atomic_dec_return(&h->ref);
-
- if (WARN_ON(cnt < 0)) {
- pr_err("%s: %s put to negative references\n",
- __func__, current->comm);
- } else if (cnt == 0)
- _nvmap_handle_free(h);
-}
-
-static inline pgprot_t nvmap_pgprot(struct nvmap_handle *h, pgprot_t prot)
-{
- if (h->flags == NVMAP_HANDLE_UNCACHEABLE)
- return pgprot_noncached(prot);
- else if (h->flags == NVMAP_HANDLE_WRITE_COMBINE)
- return pgprot_writecombine(prot);
- else if (h->flags == NVMAP_HANDLE_INNER_CACHEABLE)
- return pgprot_inner_writeback(prot);
- return prot;
-}
-#else /* CONFIG_TEGRA_NVMAP */
-struct nvmap_handle *nvmap_handle_get(struct nvmap_handle *h);
-void nvmap_handle_put(struct nvmap_handle *h);
-pgprot_t nvmap_pgprot(struct nvmap_handle *h, pgprot_t prot);
-#endif /* !CONFIG_TEGRA_NVMAP */
-
int is_nvmap_vma(struct vm_area_struct *vma);
struct nvmap_handle_ref *nvmap_alloc_iovm(struct nvmap_client *client,
@@ -268,4 +268,4 @@ struct nvmap_handle_ref *nvmap_alloc_iovm(struct nvmap_client *client,
void nvmap_free_iovm(struct nvmap_client *client, struct nvmap_handle_ref *r);
-#endif
+#endif /* __VIDEO_TEGRA_NVMAP_NVMAP_H */
diff --git a/drivers/video/tegra/nvmap/nvmap_dev.c b/drivers/video/tegra/nvmap/nvmap_dev.c
index f84f38c93aad..98b0bcc18ba5 100644
--- a/drivers/video/tegra/nvmap/nvmap_dev.c
+++ b/drivers/video/tegra/nvmap/nvmap_dev.c
@@ -34,12 +34,15 @@
#include <linux/spinlock.h>
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
+#include <linux/nvmap.h>
#include <asm/cacheflush.h>
#include <asm/tlbflush.h>
#include <mach/iovmm.h>
-#include <mach/nvmap.h>
+
+#define CREATE_TRACE_POINTS
+#include <trace/events/nvmap.h>
#include "nvmap.h"
#include "nvmap_ioctl.h"
@@ -761,6 +764,7 @@ static int nvmap_open(struct inode *inode, struct file *filp)
priv = nvmap_create_client(dev, "user");
if (!priv)
return -ENOMEM;
+ trace_nvmap_open(priv);
priv->super = (filp->f_op == &nvmap_super_fops);
@@ -772,6 +776,7 @@ static int nvmap_open(struct inode *inode, struct file *filp)
static int nvmap_release(struct inode *inode, struct file *filp)
{
+ trace_nvmap_release(filp->private_data);
nvmap_client_put(filp->private_data);
return 0;
}
@@ -973,20 +978,17 @@ static void client_stringify(struct nvmap_client *client, struct seq_file *s)
}
static void allocations_stringify(struct nvmap_client *client,
- struct seq_file *s)
+ struct seq_file *s, bool iovmm)
{
- unsigned long base = 0;
struct rb_node *n = rb_first(&client->handle_refs);
for (; n != NULL; n = rb_next(n)) {
struct nvmap_handle_ref *ref =
rb_entry(n, struct nvmap_handle_ref, node);
struct nvmap_handle *handle = ref->handle;
- if (handle->alloc && !handle->heap_pgalloc) {
- seq_printf(s, "%-18s %-18s %8lx %10u %8x\n", "", "",
- (unsigned long)(handle->carveout->base),
- handle->size, handle->userflags);
- } else if (handle->alloc && handle->heap_pgalloc) {
+ if (handle->alloc && handle->heap_pgalloc == iovmm) {
+ unsigned long base = iovmm ? 0:
+ (unsigned long)(handle->carveout->base);
seq_printf(s, "%-18s %-18s %8lx %10u %8x\n", "", "",
base, handle->size, handle->userflags);
}
@@ -1010,7 +1012,7 @@ static int nvmap_debug_allocations_show(struct seq_file *s, void *unused)
get_client_from_carveout_commit(node, commit);
client_stringify(client, s);
seq_printf(s, " %10u\n", commit->commit);
- allocations_stringify(client, s);
+ allocations_stringify(client, s, false);
seq_printf(s, "\n");
total += commit->commit;
}
@@ -1111,14 +1113,14 @@ static int nvmap_debug_iovmm_allocations_show(struct seq_file *s, void *unused)
struct nvmap_device *dev = s->private;
spin_lock_irqsave(&dev->clients_lock, flags);
- seq_printf(s, "%-18s %18s %8s %10s\n", "CLIENT", "PROCESS", "PID",
- "SIZE");
+ seq_printf(s, "%-18s %18s %8s %10s %8s\n", "CLIENT", "PROCESS", "PID",
+ "SIZE", "FLAGS");
seq_printf(s, "%-18s %18s %8s %10s\n", "", "",
"BASE", "SIZE");
list_for_each_entry(client, &dev->clients, list) {
client_stringify(client, s);
seq_printf(s, " %10u\n", atomic_read(&client->iovm_commit));
- allocations_stringify(client, s);
+ allocations_stringify(client, s, true);
seq_printf(s, "\n");
total += atomic_read(&client->iovm_commit);
}
@@ -1182,13 +1184,15 @@ static int nvmap_probe(struct platform_device *pdev)
init_waitqueue_head(&dev->iovmm_master.pin_wait);
mutex_init(&dev->iovmm_master.pin_lock);
+#ifdef CONFIG_NVMAP_PAGE_POOLS
for (i = 0; i < NVMAP_NUM_POOLS; i++)
nvmap_page_pool_init(&dev->iovmm_master.pools[i], i);
+#endif
dev->iovmm_master.iovmm =
- tegra_iovmm_alloc_client(dev_name(&pdev->dev), NULL,
+ tegra_iovmm_alloc_client(&pdev->dev, NULL,
&(dev->dev_user));
-#ifdef CONFIG_TEGRA_IOVMM
+#if defined(CONFIG_TEGRA_IOVMM) || defined(CONFIG_IOMMU_API)
if (!dev->iovmm_master.iovmm) {
e = PTR_ERR(dev->iovmm_master.iovmm);
dev_err(&pdev->dev, "couldn't create iovmm client\n");
@@ -1311,6 +1315,7 @@ static int nvmap_probe(struct platform_device *pdev)
dev, &debug_iovmm_clients_fops);
debugfs_create_file("allocations", 0664, iovmm_root,
dev, &debug_iovmm_allocations_fops);
+#ifdef CONFIG_NVMAP_PAGE_POOLS
for (i = 0; i < NVMAP_NUM_POOLS; i++) {
char name[40];
char *memtype_string[] = {"uc", "wc",
@@ -1321,6 +1326,7 @@ static int nvmap_probe(struct platform_device *pdev)
iovmm_root,
&dev->iovmm_master.pools[i].npages);
}
+#endif
}
}
diff --git a/drivers/video/tegra/nvmap/nvmap_handle.c b/drivers/video/tegra/nvmap/nvmap_handle.c
index 539b7ce9801f..05046ed8ba79 100644
--- a/drivers/video/tegra/nvmap/nvmap_handle.c
+++ b/drivers/video/tegra/nvmap/nvmap_handle.c
@@ -30,30 +30,21 @@
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/fs.h>
+#include <linux/shrinker.h>
+#include <linux/moduleparam.h>
+#include <linux/nvmap.h>
#include <asm/cacheflush.h>
#include <asm/outercache.h>
#include <asm/pgtable.h>
#include <mach/iovmm.h>
-#include <mach/nvmap.h>
-
-#include <linux/vmstat.h>
-#include <linux/swap.h>
-#include <linux/shrinker.h>
-#include <linux/moduleparam.h>
+#include <trace/events/nvmap.h>
#include "nvmap.h"
#include "nvmap_mru.h"
#include "nvmap_common.h"
-#define PRINT_CARVEOUT_CONVERSION 0
-#if PRINT_CARVEOUT_CONVERSION
-#define PR_INFO pr_info
-#else
-#define PR_INFO(...)
-#endif
-
#define NVMAP_SECURE_HEAPS (NVMAP_HEAP_CARVEOUT_IRAM | NVMAP_HEAP_IOVMM | \
NVMAP_HEAP_CARVEOUT_VPR)
#ifdef CONFIG_NVMAP_HIGHMEM_ONLY
@@ -66,6 +57,9 @@
* preserve kmalloc space, if the array of pages exceeds PAGELIST_VMALLOC_MIN,
* the array is allocated using vmalloc. */
#define PAGELIST_VMALLOC_MIN (PAGE_SIZE * 2)
+
+#ifdef CONFIG_NVMAP_PAGE_POOLS
+
#define NVMAP_TEST_PAGE_POOL_SHRINKER 1
static bool enable_pp = 1;
static int pool_size[NVMAP_NUM_POOLS];
@@ -377,6 +371,7 @@ int nvmap_page_pool_init(struct nvmap_page_pool *pool, int flags)
int i;
static int reg = 1;
struct sysinfo info;
+ int highmem_pages = 0;
typedef int (*set_pages_array) (struct page **pages, int addrinarray);
set_pages_array s_cpa[] = {
set_pages_array_uc,
@@ -395,14 +390,16 @@ int nvmap_page_pool_init(struct nvmap_page_pool *pool, int flags)
return 0;
si_meminfo(&info);
- if (!pool_size[flags]) {
+ if (!pool_size[flags] && !CONFIG_NVMAP_PAGE_POOL_SIZE)
/* Use 3/8th of total ram for page pools.
* 1/8th for uc, 1/8th for wc and 1/8th for iwb.
*/
pool->max_pages = info.totalram >> 3;
- }
+ else
+ pool->max_pages = CONFIG_NVMAP_PAGE_POOL_SIZE;
+
if (pool->max_pages <= 0 || pool->max_pages >= info.totalram)
- pool->max_pages = NVMAP_DEFAULT_PAGE_POOL_SIZE;
+ goto fail;
pool_size[flags] = pool->max_pages;
pr_info("nvmap %s page pool size=%d pages",
s_memtype_str[flags], pool->max_pages);
@@ -425,7 +422,14 @@ int nvmap_page_pool_init(struct nvmap_page_pool *pool, int flags)
__free_page(page);
goto do_cpa;
}
+ if (PageHighMem(page))
+ highmem_pages++;
}
+ si_meminfo(&info);
+ pr_info("nvmap pool = %s, highmem=%d, pool_size=%d,"
+ "totalram=%lu, freeram=%lu, totalhigh=%lu, freehigh=%lu",
+ s_memtype_str[flags], highmem_pages, pool->max_pages,
+ info.totalram, info.freeram, info.totalhigh, info.freehigh);
do_cpa:
(*s_cpa[flags])(pool->page_array, pool->npages);
nvmap_page_pool_unlock(pool);
@@ -436,6 +440,7 @@ fail:
vfree(pool->page_array);
return -ENOMEM;
}
+#endif
static inline void *altalloc(size_t len)
{
@@ -460,7 +465,9 @@ void _nvmap_handle_free(struct nvmap_handle *h)
{
struct nvmap_share *share = nvmap_get_share_from_dev(h->dev);
unsigned int i, nr_page, page_index = 0;
+#ifdef CONFIG_NVMAP_PAGE_POOLS
struct nvmap_page_pool *pool = NULL;
+#endif
if (nvmap_handle_remove(h->dev, h) != 0)
return;
@@ -481,6 +488,7 @@ void _nvmap_handle_free(struct nvmap_handle *h)
nvmap_mru_remove(share, h);
+#ifdef CONFIG_NVMAP_PAGE_POOLS
if (h->flags < NVMAP_NUM_POOLS)
pool = &share->pools[h->flags];
@@ -490,6 +498,7 @@ void _nvmap_handle_free(struct nvmap_handle *h)
break;
page_index++;
}
+#endif
if (page_index == nr_page)
goto skip_attr_restore;
@@ -538,12 +547,14 @@ static int handle_page_alloc(struct nvmap_client *client,
struct nvmap_handle *h, bool contiguous)
{
size_t size = PAGE_ALIGN(h->size);
- struct nvmap_share *share = nvmap_get_share_from_dev(h->dev);
unsigned int nr_page = size >> PAGE_SHIFT;
pgprot_t prot;
unsigned int i = 0, page_index = 0;
struct page **pages;
+#ifdef CONFIG_NVMAP_PAGE_POOLS
struct nvmap_page_pool *pool = NULL;
+ struct nvmap_share *share = nvmap_get_share_from_dev(h->dev);
+#endif
pages = altalloc(nr_page * sizeof(*pages));
if (!pages)
@@ -562,6 +573,7 @@ static int handle_page_alloc(struct nvmap_client *client,
pages[i] = nth_page(page, i);
} else {
+#ifdef CONFIG_NVMAP_PAGE_POOLS
if (h->flags < NVMAP_NUM_POOLS)
pool = &share->pools[h->flags];
@@ -572,7 +584,7 @@ static int handle_page_alloc(struct nvmap_client *client,
break;
page_index++;
}
-
+#endif
for (; i < nr_page; i++) {
pages[i] = nvmap_alloc_pages_exact(GFP_NVMAP,
PAGE_SIZE);
@@ -625,36 +637,19 @@ fail:
static void alloc_handle(struct nvmap_client *client,
struct nvmap_handle *h, unsigned int type)
{
+ unsigned int carveout_mask = NVMAP_HEAP_CARVEOUT_MASK;
+ unsigned int iovmm_mask = NVMAP_HEAP_IOVMM;
+
BUG_ON(type & (type - 1));
#ifdef CONFIG_NVMAP_CONVERT_CARVEOUT_TO_IOVMM
-#define __NVMAP_HEAP_CARVEOUT (NVMAP_HEAP_CARVEOUT_IRAM | NVMAP_HEAP_CARVEOUT_VPR)
-#define __NVMAP_HEAP_IOVMM (NVMAP_HEAP_IOVMM | NVMAP_HEAP_CARVEOUT_GENERIC)
- if (type & NVMAP_HEAP_CARVEOUT_GENERIC) {
-#ifdef CONFIG_NVMAP_ALLOW_SYSMEM
- if (h->size <= PAGE_SIZE) {
- PR_INFO("###CARVEOUT CONVERTED TO SYSMEM "
- "0x%x bytes %s(%d)###\n",
- h->size, current->comm, current->pid);
- goto sysheap;
- }
-#endif
- PR_INFO("###CARVEOUT CONVERTED TO IOVM "
- "0x%x bytes %s(%d)###\n",
- h->size, current->comm, current->pid);
- }
-#else
-#define __NVMAP_HEAP_CARVEOUT NVMAP_HEAP_CARVEOUT_MASK
-#define __NVMAP_HEAP_IOVMM NVMAP_HEAP_IOVMM
+ /* Convert generic carveout requests to iovmm requests. */
+ carveout_mask &= ~NVMAP_HEAP_CARVEOUT_GENERIC;
+ iovmm_mask |= NVMAP_HEAP_CARVEOUT_GENERIC;
#endif
- if (type & __NVMAP_HEAP_CARVEOUT) {
+ if (type & carveout_mask) {
struct nvmap_heap_block *b;
-#ifdef CONFIG_NVMAP_CONVERT_CARVEOUT_TO_IOVMM
- PR_INFO("###IRAM REQUEST RETAINED "
- "0x%x bytes %s(%d)###\n",
- h->size, current->comm, current->pid);
-#endif
/* Protect handle from relocation */
nvmap_usecount_inc(h);
@@ -668,7 +663,7 @@ static void alloc_handle(struct nvmap_client *client,
}
nvmap_usecount_dec(h);
- } else if (type & __NVMAP_HEAP_IOVMM) {
+ } else if (type & iovmm_mask) {
size_t reserved = PAGE_ALIGN(h->size);
int commit = 0;
int ret;
@@ -692,10 +687,6 @@ static void alloc_handle(struct nvmap_client *client,
}
} else if (type & NVMAP_HEAP_SYSMEM) {
-#if defined(CONFIG_NVMAP_CONVERT_CARVEOUT_TO_IOVMM) && \
- defined(CONFIG_NVMAP_ALLOW_SYSMEM)
-sysheap:
-#endif
if (handle_page_alloc(client, h, true) == 0) {
BUG_ON(!h->pgalloc.contig);
h->heap_pgalloc = true;
@@ -730,10 +721,6 @@ static const unsigned int heap_policy_large[] = {
0,
};
-/* Do not override single page policy if there is not much space to
-avoid invoking system oom killer. */
-#define NVMAP_SMALL_POLICY_SYSMEM_THRESHOLD 50000000
-
int nvmap_alloc_handle_id(struct nvmap_client *client,
unsigned long id, unsigned int heap_mask,
size_t align, unsigned int flags)
@@ -751,6 +738,7 @@ int nvmap_alloc_handle_id(struct nvmap_client *client,
if (h->alloc)
goto out;
+ trace_nvmap_alloc_handle_id(client, id, heap_mask, align, flags);
h->userflags = flags;
nr_page = ((h->size + PAGE_SIZE - 1) >> PAGE_SHIFT);
h->secure = !!(flags & NVMAP_HANDLE_SECURE);
@@ -758,32 +746,22 @@ int nvmap_alloc_handle_id(struct nvmap_client *client,
h->align = max_t(size_t, align, L1_CACHE_BYTES);
#ifndef CONFIG_TEGRA_IOVMM
+ /* convert iovmm requests to generic carveout. */
if (heap_mask & NVMAP_HEAP_IOVMM) {
- heap_mask &= NVMAP_HEAP_IOVMM;
- heap_mask |= NVMAP_HEAP_CARVEOUT_GENERIC;
+ heap_mask = (heap_mask & ~NVMAP_HEAP_IOVMM) |
+ NVMAP_HEAP_CARVEOUT_GENERIC;
}
#endif
-#ifndef CONFIG_NVMAP_CONVERT_CARVEOUT_TO_IOVMM
#ifdef CONFIG_NVMAP_ALLOW_SYSMEM
/* Allow single pages allocations in system memory to save
* carveout space and avoid extra iovm mappings */
if (nr_page == 1) {
- if (heap_mask & NVMAP_HEAP_IOVMM)
+ if (heap_mask &
+ (NVMAP_HEAP_IOVMM | NVMAP_HEAP_CARVEOUT_GENERIC))
heap_mask |= NVMAP_HEAP_SYSMEM;
- else if (heap_mask & NVMAP_HEAP_CARVEOUT_GENERIC) {
- /* Calculate size of free physical pages
- * managed by kernel */
- unsigned long freeMem =
- (global_page_state(NR_FREE_PAGES) +
- global_page_state(NR_FILE_PAGES) -
- total_swapcache_pages) << PAGE_SHIFT;
-
- if (freeMem > NVMAP_SMALL_POLICY_SYSMEM_THRESHOLD)
- heap_mask |= NVMAP_HEAP_SYSMEM;
- }
}
#endif
-
+#ifndef CONFIG_NVMAP_CONVERT_CARVEOUT_TO_IOVMM
/* This restriction is deprecated as alignments greater than
PAGE_SIZE are now correctly handled, but it is retained for
AP20 compatibility. */
@@ -843,6 +821,7 @@ void nvmap_free_handle_id(struct nvmap_client *client, unsigned long id)
return;
}
+ trace_nvmap_free_handle_id(client, id);
BUG_ON(!ref->handle);
h = ref->handle;
@@ -943,6 +922,7 @@ struct nvmap_handle_ref *nvmap_create_handle(struct nvmap_client *client,
ref->handle = h;
atomic_set(&ref->pin, 0);
add_handle_ref(client, ref);
+ trace_nvmap_create_handle(client, h, size, ref);
return ref;
}
@@ -1016,5 +996,6 @@ struct nvmap_handle_ref *nvmap_duplicate_handle_id(struct nvmap_client *client,
ref->handle = h;
atomic_set(&ref->pin, 0);
add_handle_ref(client, ref);
+ trace_nvmap_duplicate_handle_id(client, id, ref);
return ref;
}
diff --git a/drivers/video/tegra/nvmap/nvmap_heap.c b/drivers/video/tegra/nvmap/nvmap_heap.c
index 7474f31534ff..a6fe78c42f87 100644
--- a/drivers/video/tegra/nvmap/nvmap_heap.c
+++ b/drivers/video/tegra/nvmap/nvmap_heap.c
@@ -28,7 +28,7 @@
#include <linux/slab.h>
#include <linux/err.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include "nvmap.h"
#include "nvmap_heap.h"
#include "nvmap_common.h"
diff --git a/drivers/video/tegra/nvmap/nvmap_ioctl.c b/drivers/video/tegra/nvmap/nvmap_ioctl.c
index 58bc71d50469..44f00d2951a0 100644
--- a/drivers/video/tegra/nvmap/nvmap_ioctl.c
+++ b/drivers/video/tegra/nvmap/nvmap_ioctl.c
@@ -25,13 +25,14 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
+#include <linux/nvmap.h>
#include <asm/cacheflush.h>
#include <asm/outercache.h>
#include <asm/tlbflush.h>
#include <mach/iovmm.h>
-#include <mach/nvmap.h>
+#include <trace/events/nvmap.h>
#include "nvmap_ioctl.h"
#include "nvmap.h"
@@ -83,6 +84,7 @@ int nvmap_ioctl_pinop(struct file *filp, bool is_pin, void __user *arg)
on_stack[0] = (unsigned long)op.handles;
}
+ trace_nvmap_ioctl_pinop(filp->private_data, is_pin, op.count, refs);
if (is_pin)
err = nvmap_pin_ids(filp->private_data, op.count, refs);
else
@@ -234,6 +236,8 @@ int nvmap_map_into_caller_ptr(struct file *filp, void __user *arg)
if (!h)
return -EPERM;
+ trace_nvmap_map_into_caller_ptr(client, h, op.offset,
+ op.length, op.flags);
down_read(&current->mm->mmap_sem);
vma = find_vma(current->mm, op.addr);
@@ -409,6 +413,9 @@ int nvmap_ioctl_rw_handle(struct file *filp, int is_read, void __user* arg)
nvmap_usecount_inc(h);
+ trace_nvmap_ioctl_rw_handle(client, h, is_read, op.offset,
+ op.addr, op.hmem_stride,
+ op.user_stride, op.elem_size, op.count);
copied = rw_handle(client, h, is_read, op.offset,
(unsigned long)op.addr, op.hmem_stride,
op.user_stride, op.elem_size, op.count);
@@ -540,6 +547,7 @@ static bool fast_cache_maint(struct nvmap_client *client, struct nvmap_handle *h
{
int ret = false;
+#if defined(CONFIG_NVMAP_CACHE_MAINT_BY_SET_WAYS)
if ((op == NVMAP_CACHE_OP_INV) ||
((end - start) < FLUSH_CLEAN_BY_SET_WAY_THRESHOLD))
goto out;
@@ -559,6 +567,7 @@ static bool fast_cache_maint(struct nvmap_client *client, struct nvmap_handle *h
}
ret = true;
out:
+#endif
return ret;
}
@@ -580,6 +589,7 @@ static int cache_maint(struct nvmap_client *client, struct nvmap_handle *h,
goto out;
}
+ trace_cache_maint(client, h, start, end, op);
wmb();
if (h->flags == NVMAP_HANDLE_UNCACHEABLE ||
h->flags == NVMAP_HANDLE_WRITE_COMBINE || start == end)
diff --git a/drivers/video/tegra/nvmap/nvmap_ioctl.h b/drivers/video/tegra/nvmap/nvmap_ioctl.h
index 54627683ccdb..300ce9b9a6ea 100644
--- a/drivers/video/tegra/nvmap/nvmap_ioctl.h
+++ b/drivers/video/tegra/nvmap/nvmap_ioctl.h
@@ -27,7 +27,7 @@
#ifdef __KERNEL__
#include <linux/file.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#endif
enum {
diff --git a/drivers/video/tegra/nvmap/nvmap_iommu.c b/drivers/video/tegra/nvmap/nvmap_iommu.c
new file mode 100644
index 000000000000..ca868032db3f
--- /dev/null
+++ b/drivers/video/tegra/nvmap/nvmap_iommu.c
@@ -0,0 +1,97 @@
+/*
+ * IOMMU backend support for NVMAP
+ *
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/slab.h>
+#include <mach/iomap.h>
+#include <mach/iovmm.h>
+
+#include "nvmap.h"
+
+struct tegra_iovmm_area *tegra_iommu_create_vm(struct device *dev,
+ dma_addr_t req, size_t size, pgprot_t prot)
+{
+ struct tegra_iovmm_area *area;
+ dma_addr_t iova;
+
+ area = kmalloc(sizeof(*area), GFP_KERNEL);
+ if (!area)
+ return NULL;
+
+ if (!req)
+ req = DMA_ANON_ADDR;
+
+ iova = arm_iommu_alloc_iova_at(dev, req, size);
+ if (iova == DMA_ERROR_CODE)
+ goto err_out;
+ area->iovm_start = iova;
+ area->iovm_length = size;
+ area->pgprot = prot;
+ area->dev = dev;
+ return area;
+
+err_out:
+ kfree(area);
+ return NULL;
+}
+
+void tegra_iommu_free_vm(struct tegra_iovmm_area *area)
+{
+ int i;
+ size_t count = area->iovm_length >> PAGE_SHIFT;
+
+ for (i = 0; i < count; i++) {
+ dma_addr_t iova;
+
+ iova = area->iovm_start + i * PAGE_SIZE;
+ dma_unmap_page(area->dev, iova, PAGE_SIZE, DMA_NONE);
+ }
+ kfree(area);
+}
+
+struct tegra_iovmm_client *tegra_iommu_alloc_client(struct device *dev)
+{
+ struct dma_iommu_mapping *map;
+ struct tegra_iovmm_client *client;
+
+ client = kzalloc(sizeof(*client), GFP_KERNEL);
+ if (!client)
+ return NULL;
+
+ map = arm_iommu_create_mapping(&platform_bus_type,
+ TEGRA_IOMMU_BASE, TEGRA_IOMMU_SIZE, 0);
+ if (IS_ERR(map))
+ goto err_map;
+
+ if (arm_iommu_attach_device(dev, map))
+ goto err_attach;
+ client->dev = dev;
+ return client;
+
+err_attach:
+ arm_iommu_release_mapping(map);
+err_map:
+ kfree(client);
+ return NULL;
+}
+
+void tegra_iommu_free_client(struct tegra_iovmm_client *client)
+{
+ arm_iommu_release_mapping(client->dev->archdata.mapping);
+ kfree(client);
+}
diff --git a/drivers/watchdog/tegra_wdt.c b/drivers/watchdog/tegra_wdt.c
index 4fa31b25a361..0d8373efd3f1 100644
--- a/drivers/watchdog/tegra_wdt.c
+++ b/drivers/watchdog/tegra_wdt.c
@@ -3,7 +3,7 @@
*
* watchdog driver for NVIDIA tegra internal watchdog
*
- * Copyright (c) 2011, NVIDIA Corporation.
+ * Copyright (c) 2012, NVIDIA Corporation.
*
* based on drivers/watchdog/softdog.c and drivers/watchdog/omap_wdt.c
*
@@ -22,6 +22,7 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@@ -34,15 +35,20 @@
#include <linux/spinlock.h>
#include <linux/uaccess.h>
#include <linux/watchdog.h>
+#ifdef CONFIG_TEGRA_FIQ_DEBUGGER
+#include <mach/irqs.h>
+#endif
/* minimum and maximum watchdog trigger periods, in seconds */
#define MIN_WDT_PERIOD 5
#define MAX_WDT_PERIOD 1000
+/* Assign Timer 7 to Timer 10 for WDT0 to WDT3, respectively */
+#define TMR_SRC_START 7
enum tegra_wdt_status {
WDT_DISABLED = 1 << 0,
WDT_ENABLED = 1 << 1,
- WDT_IOCTL_ENABBLED_AT_PROBE = 1 << 2,
+ WDT_ENABLED_AT_PROBE = 1 << 2,
};
struct tegra_wdt {
@@ -50,15 +56,17 @@ struct tegra_wdt {
struct notifier_block notifier;
struct resource *res_src;
struct resource *res_wdt;
+ struct resource *res_int_base;
unsigned long users;
void __iomem *wdt_source;
void __iomem *wdt_timer;
+ void __iomem *int_base;
int irq;
+ int tmrsrc;
int timeout;
int status;
};
-static struct platform_device *tegra_wdt_dev;
/*
* For spinlock lockup detection to work, the heartbeat should be 2*lockup
* for cases where the spinlock disabled irqs.
@@ -117,39 +125,41 @@ static irqreturn_t tegra_wdt_interrupt(int irq, void *dev_id)
#define TIMER_PCR 0x4
#define TIMER_PCR_INTR (1 << 30)
#define WDT_CFG (0)
- #define WDT_CFG_TMR_SRC (0 << 0) /* for TMR10. */
#define WDT_CFG_PERIOD (1 << 4)
#define WDT_CFG_INT_EN (1 << 12)
+ #define WDT_CFG_FIQ_INT_EN (1 << 13)
#define WDT_CFG_SYS_RST_EN (1 << 14)
#define WDT_CFG_PMC2CAR_RST_EN (1 << 15)
+#define WDT_STATUS (4)
+ #define WDT_INTR_STAT (1 << 1)
#define WDT_CMD (8)
#define WDT_CMD_START_COUNTER (1 << 0)
#define WDT_CMD_DISABLE_COUNTER (1 << 1)
#define WDT_UNLOCK (0xC)
#define WDT_UNLOCK_PATTERN (0xC45A << 0)
+#define ICTLR_IEP_CLASS 0x2C
+#define MAX_NR_CPU_WDT 0x4
-static void tegra_wdt_set_timeout(struct tegra_wdt *wdt, int sec)
-{
- u32 ptv;
-
- ptv = readl(wdt->wdt_timer + TIMER_PTV);
-
- wdt->timeout = clamp(sec, MIN_WDT_PERIOD, MAX_WDT_PERIOD);
- if (ptv & TIMER_EN) {
- /* since the watchdog reset occurs when a fourth interrupt
- * is asserted before the first is processed, program the
- * timer period to one-fourth of the watchdog period */
- ptv = (wdt->timeout * 1000000ul) / 4;
- ptv |= (TIMER_EN | TIMER_PERIODIC);
- writel(ptv, wdt->wdt_timer + TIMER_PTV);
- }
-}
+struct tegra_wdt *tegra_wdt[MAX_NR_CPU_WDT];
static inline void tegra_wdt_ping(struct tegra_wdt *wdt)
{
writel(WDT_CMD_START_COUNTER, wdt->wdt_source + WDT_CMD);
}
+#ifdef CONFIG_TEGRA_FIQ_DEBUGGER
+static void tegra_wdt_int_priority(struct tegra_wdt *wdt)
+{
+ unsigned val = 0;
+
+ if (!wdt->int_base)
+ return;
+ val = readl(wdt->int_base + ICTLR_IEP_CLASS);
+ val &= ~(1 << (INT_WDT_CPU & 31));
+ writel(val, wdt->int_base + ICTLR_IEP_CLASS);
+}
+#endif
+
static void tegra_wdt_enable(struct tegra_wdt *wdt)
{
u32 val;
@@ -159,8 +169,17 @@ static void tegra_wdt_enable(struct tegra_wdt *wdt)
val |= (TIMER_EN | TIMER_PERIODIC);
writel(val, wdt->wdt_timer + TIMER_PTV);
- val = WDT_CFG_TMR_SRC | WDT_CFG_PERIOD | /*WDT_CFG_INT_EN |*/
+ /* Interrupt handler is not required for user space
+ * WDT accesses, since the caller is responsible to ping the
+ * WDT to reset the counter before expiration, through ioctls.
+ * SYS_RST_EN doesnt work as there is no external reset
+ * from Tegra.
+ */
+ val = wdt->tmrsrc | WDT_CFG_PERIOD | /*WDT_CFG_INT_EN |*/
/*WDT_CFG_SYS_RST_EN |*/ WDT_CFG_PMC2CAR_RST_EN;
+#ifdef CONFIG_TEGRA_FIQ_DEBUGGER
+ val |= WDT_CFG_FIQ_INT_EN;
+#endif
writel(val, wdt->wdt_source + WDT_CFG);
writel(WDT_CMD_START_COUNTER, wdt->wdt_source + WDT_CMD);
}
@@ -175,9 +194,17 @@ static void tegra_wdt_disable(struct tegra_wdt *wdt)
static irqreturn_t tegra_wdt_interrupt(int irq, void *dev_id)
{
- struct tegra_wdt *wdt = dev_id;
+ unsigned i, status;
+
+ for (i = 0; i < MAX_NR_CPU_WDT; i++) {
+ if (tegra_wdt[i] == NULL)
+ continue;
+ status = readl(tegra_wdt[i]->wdt_source + WDT_STATUS);
+ if ((tegra_wdt[i]->status & WDT_ENABLED) &&
+ (status & WDT_INTR_STAT))
+ tegra_wdt_ping(tegra_wdt[i]);
+ }
- tegra_wdt_ping(wdt);
return IRQ_HANDLED;
}
#endif
@@ -194,7 +221,9 @@ static int tegra_wdt_notify(struct notifier_block *this,
static int tegra_wdt_open(struct inode *inode, struct file *file)
{
- struct tegra_wdt *wdt = platform_get_drvdata(tegra_wdt_dev);
+ struct miscdevice *mdev = file->private_data;
+ struct tegra_wdt *wdt = container_of(mdev, struct tegra_wdt,
+ miscdev);
if (test_and_set_bit(1, &wdt->users))
return -EBUSY;
@@ -301,30 +330,39 @@ static const struct file_operations tegra_wdt_fops = {
static int tegra_wdt_probe(struct platform_device *pdev)
{
- struct resource *res_src, *res_wdt, *res_irq;
+ struct resource *res_src, *res_wdt, *res_irq, *res_int_base;
struct tegra_wdt *wdt;
u32 src;
int ret = 0;
+ u32 val = 0;
- if (pdev->id != -1) {
- dev_err(&pdev->dev, "only id -1 supported\n");
+ if (pdev->id < -1 && pdev->id > 3) {
+ dev_err(&pdev->dev, "only IDs 3:0 supported\n");
return -ENODEV;
}
- if (tegra_wdt_dev != NULL) {
- dev_err(&pdev->dev, "watchdog already registered\n");
- return -EIO;
- }
-
res_src = platform_get_resource(pdev, IORESOURCE_MEM, 0);
res_wdt = platform_get_resource(pdev, IORESOURCE_MEM, 1);
res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!res_src || !res_wdt || !res_irq) {
+ if (!res_src || !res_wdt || (!pdev->id && !res_irq)) {
dev_err(&pdev->dev, "incorrect resources\n");
return -ENOENT;
}
+#ifdef CONFIG_TEGRA_FIQ_DEBUGGER
+ res_int_base = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ if (!pdev->id && !res_int_base) {
+ dev_err(&pdev->dev, "FIQ_DBG: INT base not defined\n");
+ return -ENOENT;
+ }
+#endif
+
+ if (pdev->id == -1 && !res_irq) {
+ dev_err(&pdev->dev, "incorrect irq\n");
+ return -ENOENT;
+ }
+
wdt = kzalloc(sizeof(*wdt), GFP_KERNEL);
if (!wdt) {
dev_err(&pdev->dev, "out of memory\n");
@@ -333,8 +371,20 @@ static int tegra_wdt_probe(struct platform_device *pdev)
wdt->irq = -1;
wdt->miscdev.parent = &pdev->dev;
- wdt->miscdev.minor = WATCHDOG_MINOR;
- wdt->miscdev.name = "watchdog";
+ if (pdev->id == -1) {
+ wdt->miscdev.minor = WATCHDOG_MINOR;
+ wdt->miscdev.name = "watchdog";
+ } else {
+ wdt->miscdev.minor = MISC_DYNAMIC_MINOR;
+ if (pdev->id == 0)
+ wdt->miscdev.name = "watchdog0";
+ else if (pdev->id == 1)
+ wdt->miscdev.name = "watchdog1";
+ else if (pdev->id == 2)
+ wdt->miscdev.name = "watchdog2";
+ else if (pdev->id == 3)
+ wdt->miscdev.name = "watchdog3";
+ }
wdt->miscdev.fops = &tegra_wdt_fops;
wdt->notifier.notifier_call = tegra_wdt_notify;
@@ -352,6 +402,8 @@ static int tegra_wdt_probe(struct platform_device *pdev)
wdt->wdt_source = ioremap(res_src->start, resource_size(res_src));
wdt->wdt_timer = ioremap(res_wdt->start, resource_size(res_wdt));
+ /* tmrsrc will be used to set WDT_CFG */
+ wdt->tmrsrc = (TMR_SRC_START + pdev->id) % 10;
if (!wdt->wdt_source || !wdt->wdt_timer) {
dev_err(&pdev->dev, "unable to map registers\n");
ret = -ENOMEM;
@@ -365,16 +417,38 @@ static int tegra_wdt_probe(struct platform_device *pdev)
tegra_wdt_disable(wdt);
writel(TIMER_PCR_INTR, wdt->wdt_timer + TIMER_PCR);
- ret = request_irq(res_irq->start, tegra_wdt_interrupt, IRQF_DISABLED,
- dev_name(&pdev->dev), wdt);
- if (ret) {
- dev_err(&pdev->dev, "unable to configure IRQ\n");
- goto fail;
+ if (res_irq != NULL) {
+#ifdef CONFIG_TEGRA_FIQ_DEBUGGER
+ /* FIQ debugger enables FIQ priority for INT_WDT_CPU.
+ * But that will disable IRQ on WDT expiration.
+ * Reset the priority back to IRQ on INT_WDT_CPU so
+ * that tegra_wdt_interrupt gets its chance to restart the
+ * counter before expiration.
+ */
+ res_int_base = request_mem_region(res_int_base->start,
+ resource_size(res_int_base),
+ pdev->name);
+ if (!res_int_base)
+ goto fail;
+ wdt->int_base = ioremap(res_int_base->start,
+ resource_size(res_int_base));
+ if (!wdt->int_base)
+ goto fail;
+ tegra_wdt_int_priority(wdt);
+#endif
+ ret = request_irq(res_irq->start, tegra_wdt_interrupt,
+ IRQF_DISABLED, dev_name(&pdev->dev), wdt);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to configure IRQ\n");
+ goto fail;
+ }
+ wdt->irq = res_irq->start;
}
- wdt->irq = res_irq->start;
wdt->res_src = res_src;
wdt->res_wdt = res_wdt;
+ wdt->res_int_base = res_int_base;
+ wdt->status = WDT_DISABLED;
ret = register_reboot_notifier(&wdt->notifier);
if (ret) {
@@ -390,14 +464,23 @@ static int tegra_wdt_probe(struct platform_device *pdev)
}
platform_set_drvdata(pdev, wdt);
- tegra_wdt_dev = pdev;
+
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
#ifdef CONFIG_TEGRA_WATCHDOG_ENABLE_ON_PROBE
- wdt->status = WDT_ENABLED | WDT_ENABLED_AT_PROBE;
- wdt->timeout = heartbeat;
- tegra_wdt_enable(wdt);
-#else
- wdt->status = WDT_DISABLED;
+ /* Init and enable watchdog on WDT0 with timer 8 during probe */
+ if (!(pdev->id)) {
+ wdt->status = WDT_ENABLED | WDT_ENABLED_AT_PROBE;
+ wdt->timeout = heartbeat;
+ tegra_wdt_enable(wdt);
+ val = readl(wdt->wdt_source + WDT_CFG);
+ val |= WDT_CFG_INT_EN;
+ writel(val, wdt->wdt_source + WDT_CFG);
+ pr_info("WDT heartbeat enabled on probe\n");
+ }
+#endif
+ tegra_wdt[pdev->id] = wdt;
#endif
+ pr_info("%s done\n", __func__);
return 0;
fail:
if (wdt->irq != -1)
@@ -406,10 +489,15 @@ fail:
iounmap(wdt->wdt_source);
if (wdt->wdt_timer)
iounmap(wdt->wdt_timer);
+ if (wdt->int_base)
+ iounmap(wdt->int_base);
if (res_src)
release_mem_region(res_src->start, resource_size(res_src));
if (res_wdt)
release_mem_region(res_wdt->start, resource_size(res_wdt));
+ if (res_int_base)
+ release_mem_region(res_int_base->start,
+ resource_size(res_int_base));
kfree(wdt);
return ret;
}
@@ -422,11 +510,17 @@ static int tegra_wdt_remove(struct platform_device *pdev)
unregister_reboot_notifier(&wdt->notifier);
misc_deregister(&wdt->miscdev);
- free_irq(wdt->irq, wdt);
+ if (wdt->irq != -1)
+ free_irq(wdt->irq, wdt);
iounmap(wdt->wdt_source);
iounmap(wdt->wdt_timer);
+ if (wdt->int_base)
+ iounmap(wdt->int_base);
release_mem_region(wdt->res_src->start, resource_size(wdt->res_src));
release_mem_region(wdt->res_wdt->start, resource_size(wdt->res_wdt));
+ if (wdt->res_int_base)
+ release_mem_region(wdt->res_int_base->start,
+ resource_size(wdt->res_int_base));
kfree(wdt);
platform_set_drvdata(pdev, NULL);
return 0;
@@ -448,6 +542,16 @@ static int tegra_wdt_resume(struct platform_device *pdev)
if (wdt->status & WDT_ENABLED)
tegra_wdt_enable(wdt);
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+ /* Enable interrupt for WDT3 heartbeat watchdog */
+ if (wdt->status & WDT_ENABLED_AT_PROBE) {
+ u32 val = 0;
+ val = readl(wdt->wdt_source + WDT_CFG);
+ val |= WDT_CFG_INT_EN;
+ writel(val, wdt->wdt_source + WDT_CFG);
+ pr_info("WDT heartbeat enabled on probe\n");
+ }
+#endif
return 0;
}
#endif
@@ -488,4 +592,3 @@ MODULE_PARM_DESC(heartbeat,
MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
MODULE_ALIAS("platform:tegra_wdt");
-