summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/driver-model/devres.txt4
-rw-r--r--arch/arm/Kconfig20
-rw-r--r--arch/arm/common/fiq_debugger.c3
-rw-r--r--arch/arm/configs/tegra3_android_defconfig22
-rw-r--r--arch/arm/configs/tegra3_defconfig11
-rw-r--r--arch/arm/configs/tegra_android_defconfig7
-rw-r--r--arch/arm/configs/tegra_defconfig3
-rw-r--r--arch/arm/configs/tegra_p1852_gnu_linux_defconfig7
-rw-r--r--arch/arm/configs/tegra_p852_gnu_linux_defconfig1
-rw-r--r--arch/arm/include/asm/dma-mapping.h36
-rw-r--r--arch/arm/include/asm/mach/map.h2
-rw-r--r--arch/arm/include/asm/memory.h7
-rw-r--r--arch/arm/kernel/sleep.S4
-rw-r--r--arch/arm/mach-tegra/Kconfig55
-rw-r--r--arch/arm/mach-tegra/Makefile16
-rw-r--r--arch/arm/mach-tegra/ahb.c3
-rw-r--r--arch/arm/mach-tegra/apbio.c24
-rw-r--r--arch/arm/mach-tegra/apbio.h12
-rw-r--r--arch/arm/mach-tegra/baseband-xmm-power.c815
-rw-r--r--arch/arm/mach-tegra/baseband-xmm-power.h25
-rw-r--r--arch/arm/mach-tegra/baseband-xmm-power2.c525
-rw-r--r--arch/arm/mach-tegra/board-aruba-panel.c5
-rw-r--r--arch/arm/mach-tegra/board-aruba-power.c1
-rw-r--r--arch/arm/mach-tegra/board-aruba.c8
-rw-r--r--arch/arm/mach-tegra/board-cardhu-kbc.c15
-rw-r--r--arch/arm/mach-tegra/board-cardhu-memory.c722
-rw-r--r--arch/arm/mach-tegra/board-cardhu-panel.c661
-rw-r--r--arch/arm/mach-tegra/board-cardhu-pinmux.c46
-rw-r--r--arch/arm/mach-tegra/board-cardhu-pm298-power-rails.c11
-rw-r--r--arch/arm/mach-tegra/board-cardhu-pm299-power-rails.c11
-rw-r--r--arch/arm/mach-tegra/board-cardhu-power.c70
-rw-r--r--arch/arm/mach-tegra/board-cardhu-sdhci.c21
-rw-r--r--arch/arm/mach-tegra/board-cardhu-sensors.c219
-rw-r--r--arch/arm/mach-tegra/board-cardhu.c586
-rw-r--r--arch/arm/mach-tegra/board-cardhu.h5
-rw-r--r--arch/arm/mach-tegra/board-enterprise-baseband.c165
-rw-r--r--arch/arm/mach-tegra/board-enterprise-memory.c735
-rw-r--r--arch/arm/mach-tegra/board-enterprise-panel.c58
-rw-r--r--arch/arm/mach-tegra/board-enterprise-pinmux.c10
-rw-r--r--arch/arm/mach-tegra/board-enterprise-power.c76
-rw-r--r--arch/arm/mach-tegra/board-enterprise-sdhci.c12
-rw-r--r--arch/arm/mach-tegra/board-enterprise-sensors.c9
-rw-r--r--arch/arm/mach-tegra/board-enterprise.c380
-rw-r--r--arch/arm/mach-tegra/board-enterprise.h3
-rw-r--r--arch/arm/mach-tegra/board-harmony-panel.c5
-rw-r--r--arch/arm/mach-tegra/board-harmony-pcie.c3
-rw-r--r--arch/arm/mach-tegra/board-harmony.c155
-rw-r--r--arch/arm/mach-tegra/board-kai-kbc.c10
-rw-r--r--arch/arm/mach-tegra/board-kai-panel.c74
-rw-r--r--arch/arm/mach-tegra/board-kai-pinmux.c8
-rw-r--r--arch/arm/mach-tegra/board-kai-power.c21
-rw-r--r--arch/arm/mach-tegra/board-kai-sdhci.c18
-rw-r--r--arch/arm/mach-tegra/board-kai-sensors.c118
-rw-r--r--arch/arm/mach-tegra/board-kai.c251
-rw-r--r--arch/arm/mach-tegra/board-kai.h3
-rw-r--r--arch/arm/mach-tegra/board-p1852-panel.c64
-rw-r--r--arch/arm/mach-tegra/board-p1852-pinmux.c213
-rw-r--r--arch/arm/mach-tegra/board-p1852-sdhci.c17
-rw-r--r--arch/arm/mach-tegra/board-p1852.c357
-rw-r--r--arch/arm/mach-tegra/board-p1852.h6
-rw-r--r--arch/arm/mach-tegra/board-trimslice.c3
-rw-r--r--arch/arm/mach-tegra/board-ventana-panel.c34
-rw-r--r--arch/arm/mach-tegra/board-ventana-pinmux.c4
-rw-r--r--arch/arm/mach-tegra/board-ventana-power.c13
-rw-r--r--arch/arm/mach-tegra/board-ventana-sdhci.c13
-rw-r--r--arch/arm/mach-tegra/board-ventana-sensors.c149
-rw-r--r--arch/arm/mach-tegra/board-ventana.c250
-rw-r--r--arch/arm/mach-tegra/board-whistler-baseband.c154
-rw-r--r--arch/arm/mach-tegra/board-whistler-panel.c23
-rw-r--r--arch/arm/mach-tegra/board-whistler-pinmux.c14
-rw-r--r--arch/arm/mach-tegra/board-whistler-power.c1
-rw-r--r--arch/arm/mach-tegra/board-whistler-sdhci.c11
-rw-r--r--arch/arm/mach-tegra/board-whistler-sensors.c16
-rw-r--r--arch/arm/mach-tegra/board-whistler.c154
-rw-r--r--arch/arm/mach-tegra/board.h17
-rw-r--r--arch/arm/mach-tegra/clock.c32
-rw-r--r--arch/arm/mach-tegra/clock.h12
-rw-r--r--arch/arm/mach-tegra/common-t2.c6
-rw-r--r--arch/arm/mach-tegra/common.c149
-rw-r--r--arch/arm/mach-tegra/cpu-tegra.c13
-rw-r--r--arch/arm/mach-tegra/cpu-tegra.h1
-rw-r--r--arch/arm/mach-tegra/cpu-tegra3.c90
-rw-r--r--arch/arm/mach-tegra/cpuquiet.c433
-rw-r--r--arch/arm/mach-tegra/devices.c133
-rw-r--r--arch/arm/mach-tegra/devices.h11
-rw-r--r--arch/arm/mach-tegra/dvfs.c25
-rw-r--r--arch/arm/mach-tegra/dvfs.h23
-rw-r--r--arch/arm/mach-tegra/headsmp.S4
-rw-r--r--arch/arm/mach-tegra/include/mach/clk.h12
-rw-r--r--arch/arm/mach-tegra/include/mach/dc.h23
-rw-r--r--arch/arm/mach-tegra/include/mach/iomap.h9
-rw-r--r--arch/arm/mach-tegra/include/mach/iovmm.h67
-rw-r--r--arch/arm/mach-tegra/include/mach/latency_allowance.h4
-rw-r--r--arch/arm/mach-tegra/include/mach/legacy_irq.h2
-rw-r--r--arch/arm/mach-tegra/include/mach/sdhci.h9
-rw-r--r--arch/arm/mach-tegra/include/mach/tegra_p1852_pdata.h7
-rw-r--r--arch/arm/mach-tegra/include/mach/tegra_usb_modem_power.h12
-rw-r--r--arch/arm/mach-tegra/include/mach/thermal.h91
-rw-r--r--arch/arm/mach-tegra/include/mach/usb_phy.h239
-rw-r--r--arch/arm/mach-tegra/iovmm-gart.c6
-rw-r--r--arch/arm/mach-tegra/iovmm-smmu.c50
-rw-r--r--arch/arm/mach-tegra/iovmm.c2
-rw-r--r--arch/arm/mach-tegra/irq.c52
-rw-r--r--arch/arm/mach-tegra/p852/board-p852-panel.c5
-rw-r--r--arch/arm/mach-tegra/p852/board-p852.c144
-rw-r--r--arch/arm/mach-tegra/p852/board-p852.h1
-rw-r--r--arch/arm/mach-tegra/pcie.c569
-rw-r--r--arch/arm/mach-tegra/pinmux-t2-tables.c4
-rw-r--r--arch/arm/mach-tegra/pinmux-t3-tables.c473
-rw-r--r--arch/arm/mach-tegra/platsmp.c5
-rw-r--r--arch/arm/mach-tegra/pm-irq.c63
-rw-r--r--arch/arm/mach-tegra/pm-irq.h2
-rw-r--r--arch/arm/mach-tegra/pm.c28
-rw-r--r--arch/arm/mach-tegra/powergate.c2
-rw-r--r--arch/arm/mach-tegra/sleep-t3.S5
-rw-r--r--arch/arm/mach-tegra/sleep.h10
-rw-r--r--arch/arm/mach-tegra/syncpt.c100
-rw-r--r--arch/arm/mach-tegra/tegra2_clocks.c47
-rw-r--r--arch/arm/mach-tegra/tegra2_host1x_devices.h26
-rw-r--r--arch/arm/mach-tegra/tegra2_mc.c9
-rw-r--r--arch/arm/mach-tegra/tegra2_usb_phy.c1938
-rw-r--r--arch/arm/mach-tegra/tegra3_actmon.c4
-rw-r--r--arch/arm/mach-tegra/tegra3_clocks.c301
-rw-r--r--arch/arm/mach-tegra/tegra3_dvfs.c276
-rw-r--r--arch/arm/mach-tegra/tegra3_emc.c241
-rw-r--r--arch/arm/mach-tegra/tegra3_emc.h4
-rw-r--r--arch/arm/mach-tegra/tegra3_host1x_devices.h26
-rw-r--r--arch/arm/mach-tegra/tegra3_speedo.c37
-rw-r--r--arch/arm/mach-tegra/tegra3_thermal.c712
-rw-r--r--arch/arm/mach-tegra/tegra3_throttle.c326
-rw-r--r--arch/arm/mach-tegra/tegra3_tsensor.c6
-rw-r--r--arch/arm/mach-tegra/tegra3_usb_phy.c2870
-rw-r--r--arch/arm/mach-tegra/tegra_odm_fuses.c2
-rw-r--r--arch/arm/mach-tegra/tegra_usb_modem_power.c331
-rw-r--r--arch/arm/mach-tegra/tegra_usb_phy.h107
-rw-r--r--arch/arm/mach-tegra/timer-t3.c7
-rw-r--r--arch/arm/mach-tegra/usb_phy.c3460
-rw-r--r--arch/arm/mach-tegra/wakeups-t2.c120
-rw-r--r--arch/arm/mach-tegra/wakeups-t2.h62
-rw-r--r--arch/arm/mach-tegra/wakeups-t3.c140
-rw-r--r--arch/arm/mach-tegra/wakeups-t3.h76
-rw-r--r--arch/arm/mach-tegra/wakeups.c130
-rw-r--r--arch/arm/mach-tegra/wakeups.h48
-rw-r--r--arch/arm/mach-tegra/wdt-recovery.c10
-rw-r--r--arch/arm/mm/Kconfig11
-rw-r--r--arch/arm/mm/Makefile8
-rw-r--r--arch/arm/mm/dma-na-mapping.c748
-rw-r--r--arch/arm/mm/init.c3
-rw-r--r--arch/arm/mm/mm.h5
-rw-r--r--arch/arm/mm/mmu.c36
-rw-r--r--arch/arm/mm/pageattr.c9
-rw-r--r--arch/arm/mm/proc-v7.S6
-rw-r--r--arch/arm/vfp/vfpmodule.c16
-rw-r--r--chromeos/config/armel/config.common.armel537
-rw-r--r--chromeos/config/armel/config.flavour.chromeos-tegra3124
-rw-r--r--chromeos/config/armel/config.flavour.chromiumos-arm85
-rw-r--r--chromeos/config/config.common.chromeos2042
-rw-r--r--chromeos/config/i386/config.common.i386752
l---------chromeos/config/i386/config.flavour.chromeos-intel-menlow1
-rw-r--r--chromeos/config/i386/config.flavour.chromeos-pinetrail-i38641
-rw-r--r--chromeos/config/i386/config.flavour.chromiumos-i38685
-rw-r--r--chromeos/config/x86_64/config.common.x86_64743
-rw-r--r--chromeos/config/x86_64/config.flavour.chromeos-intel-pineview3
-rwxr-xr-xchromeos/scripts/allconfigs28
-rwxr-xr-xchromeos/scripts/kernelconfig123
-rwxr-xr-xchromeos/scripts/prepareconfig18
-rwxr-xr-xchromeos/scripts/splitconfig49
-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
-rw-r--r--fs/fat/dir.c2
-rw-r--r--fs/proc/loadavg.c6
-rw-r--r--include/linux/clk.h32
-rw-r--r--include/linux/cpufreq.h1
-rw-r--r--include/linux/cpuquiet.h105
-rw-r--r--include/linux/i2c/twl.h16
-rw-r--r--include/linux/lightsensor.h1
-rw-r--r--include/linux/mfd/palmas.h2620
-rw-r--r--include/linux/mfd/rc5t583.h78
-rw-r--r--include/linux/mfd/tps65910.h49
-rw-r--r--include/linux/mfd/tps80031.h1
-rw-r--r--include/linux/mmc/card.h8
-rw-r--r--include/linux/mmc/core.h5
-rw-r--r--include/linux/nct1008.h11
-rw-r--r--include/linux/nl80211.h16
-rw-r--r--include/linux/nvhost.h126
-rw-r--r--include/linux/nvmap.h (renamed from arch/arm/mach-tegra/include/mach/nvmap.h)61
-rw-r--r--include/linux/of.h2
-rw-r--r--include/linux/platform_data/tegra_usb.h145
-rw-r--r--include/linux/pm_qos_params.h2
-rw-r--r--include/linux/regmap.h2
-rw-r--r--include/linux/regulator/max8973-regulator.h77
-rw-r--r--include/linux/regulator/tps62360.h2
-rw-r--r--include/linux/regulator/tps6238x0-regulator.h46
-rw-r--r--include/linux/regulator/tps80031-regulator.h4
-rw-r--r--include/linux/sched.h1
-rw-r--r--include/linux/smb349-charger.h12
-rw-r--r--include/linux/tegra_audio.h4
-rw-r--r--include/linux/tegra_pwm_bl.h1
-rw-r--r--include/linux/therm_est.h77
-rw-r--r--include/media/ad5816.h79
-rw-r--r--include/media/ar0832_main.h13
-rw-r--r--include/media/nvc_focus.h53
-rw-r--r--include/media/ov2710.h11
-rw-r--r--include/media/ov5640.h64
-rw-r--r--include/media/ov5650.h6
-rw-r--r--include/media/tegra_camera.h4
-rw-r--r--include/net/cfg80211.h15
-rw-r--r--include/trace/events/nvhost.h148
-rw-r--r--include/trace/events/nvmap.h304
-rw-r--r--include/trace/events/power.h22
-rw-r--r--include/video/tegra_dc_ext.h13
-rw-r--r--kernel/gcov/gcc_3_4.c12
-rw-r--r--kernel/gcov/gcov.h11
-rw-r--r--kernel/sched.c67
-rw-r--r--kernel/sched_debug.c3
-rw-r--r--kernel/sched_rt.c1
-rw-r--r--net/mac80211/ieee80211_i.h6
-rw-r--r--net/mac80211/scan.c50
-rw-r--r--net/wireless/nl80211.c9
-rw-r--r--security/tf_driver/Makefile2
-rw-r--r--security/tf_driver/s_version.h4
-rw-r--r--security/tf_driver/tf_comm_tz.c18
-rw-r--r--security/tf_driver/tf_device.c17
-rw-r--r--security/tf_driver/tf_protocol.h4
-rw-r--r--sound/soc/codecs/Makefile3
-rw-r--r--sound/soc/codecs/aic326x_tiload.c5
-rw-r--r--sound/soc/codecs/base_main_Rate48_pps_driver.h11
-rw-r--r--sound/soc/codecs/max98088.c29
-rw-r--r--sound/soc/codecs/max98088.h5
-rw-r--r--sound/soc/codecs/rt5639.c26
-rw-r--r--sound/soc/codecs/rt5640.c56
-rw-r--r--sound/soc/codecs/second_rate_pps_driver.h7
-rw-r--r--sound/soc/codecs/spdif_transciever.c2
-rw-r--r--sound/soc/codecs/tlv320aic326x.c24
-rw-r--r--sound/soc/codecs/tlv320aic326x.h11
-rw-r--r--sound/soc/codecs/tlv320aic326x_mini-dsp.c32
-rw-r--r--sound/soc/codecs/tlv320aic326x_minidsp_config.c11
-rw-r--r--sound/soc/codecs/wm8903.c2
-rw-r--r--sound/soc/sh/siu_pcm.c5
-rw-r--r--sound/soc/tegra/Makefile2
-rw-r--r--sound/soc/tegra/tegra20_das.c6
-rw-r--r--sound/soc/tegra/tegra20_das.h4
-rw-r--r--sound/soc/tegra/tegra30_ahub.c78
-rw-r--r--sound/soc/tegra/tegra30_ahub.h10
-rw-r--r--sound/soc/tegra/tegra30_dam.c47
-rw-r--r--sound/soc/tegra/tegra30_i2s.c175
-rw-r--r--sound/soc/tegra/tegra_aic326x.c4
-rw-r--r--sound/soc/tegra/tegra_asoc_utils.c138
-rw-r--r--sound/soc/tegra/tegra_asoc_utils.h4
-rw-r--r--sound/soc/tegra/tegra_max98088.c16
-rw-r--r--sound/soc/tegra/tegra_max98095.c17
-rw-r--r--sound/soc/tegra/tegra_p1852.c45
-rw-r--r--sound/soc/tegra/tegra_pcm.c26
-rw-r--r--sound/soc/tegra/tegra_pcm.h1
-rw-r--r--sound/soc/tegra/tegra_rt5640.c5
-rw-r--r--sound/soc/tegra/tegra_wm8753.c5
-rw-r--r--sound/soc/tegra/tegra_wm8903.c6
628 files changed, 65399 insertions, 20309 deletions
diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt
index 10c64c8a13d4..6346042c3b54 100644
--- a/Documentation/driver-model/devres.txt
+++ b/Documentation/driver-model/devres.txt
@@ -267,3 +267,7 @@ IOMAP
pcim_iounmap()
pcim_iomap_table() : array of mapped addresses indexed by BAR
pcim_iomap_regions() : do request_region() and iomap() on multiple BARs
+
+CLOCK
+ devm_clk_get()
+ devm_clk_put()
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 3c3b868948aa..16b259ab7aac 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1155,6 +1155,14 @@ config ARM_ERRATA_460075
ACTLR register. Note that setting specific bits in the ACTLR register
may not be available in non-secure mode.
+config ARM_ERRATA_716044
+ bool "ARM errata: an uncacheable load multiple instruction can cause a deadlock"
+ depends on CPU_V7
+ help
+ Under some rare circumstances, an uncacheable load multiple
+ instruction (LDRD, LDM, VLDM, VLD1, VLD2, VLD3, VLD4) can cause
+ a processor deadlock.
+
config ARM_ERRATA_742230
bool "ARM errata: DMB operation may be faulty"
depends on CPU_V7 && SMP
@@ -1396,6 +1404,8 @@ config PCI_HOST_ITE8152
source "drivers/pci/Kconfig"
+source "drivers/pci/pcie/Kconfig"
+
source "drivers/pcmcia/Kconfig"
endmenu
@@ -1688,6 +1698,14 @@ config HW_PERF_EVENTS
Enable hardware performance counter support for perf events. If
disabled, perf events will use software events only.
+config ARCH_HAS_SUSPEND_PAGETABLE
+ bool
+ help
+ This option indicates the platform architecture installs its own
+ 1:1 pagetable during CPU suspend/resume codepaths. This means the
+ patching of the pagetable as part of reenabling the MMU isn't
+ needed in the ARM common CPU resume codepath. If in doubt, say N.
+
source "mm/Kconfig"
config FORCE_MAX_ZONEORDER
@@ -2103,6 +2121,8 @@ endif
source "drivers/cpuidle/Kconfig"
+source "drivers/cpuquiet/Kconfig"
+
endmenu
menu "Floating point emulation"
diff --git a/arch/arm/common/fiq_debugger.c b/arch/arm/common/fiq_debugger.c
index 3ed18ae2ed80..a98d4a3b8fac 100644
--- a/arch/arm/common/fiq_debugger.c
+++ b/arch/arm/common/fiq_debugger.c
@@ -827,6 +827,9 @@ static void debug_fiq(struct fiq_glue_handler *h, void *regs, void *svc_sp)
unsigned int this_cpu = THREAD_INFO(svc_sp)->cpu;
bool need_irq;
+ /* Spew regs and callstack immediately after entering FIQ handler */
+ debug_fiq_exec(state, "allregs", regs, svc_sp);
+ debug_fiq_exec(state, "bt", regs, svc_sp);
need_irq = debug_handle_uart_interrupt(state, this_cpu, regs, svc_sp);
if (need_irq)
debug_force_irq(state);
diff --git a/arch/arm/configs/tegra3_android_defconfig b/arch/arm/configs/tegra3_android_defconfig
index 4aab2283e215..0ab4493d3205 100644
--- a/arch/arm/configs/tegra3_android_defconfig
+++ b/arch/arm/configs/tegra3_android_defconfig
@@ -26,6 +26,9 @@ CONFIG_ARCH_TEGRA=y
CONFIG_GPIO_PCA953X=y
CONFIG_ARCH_TEGRA_3x_SOC=y
CONFIG_TEGRA_PCI=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCIEASPM=y
+CONFIG_PCIEASPM_POWERSAVE=y
CONFIG_MACH_CARDHU=y
CONFIG_MACH_TEGRA_ENTERPRISE=y
CONFIG_MACH_KAI=y
@@ -173,13 +176,13 @@ CONFIG_BT_HCIUART=y
CONFIG_BT_HCIUART_H4=y
CONFIG_BT_HCIUART_LL=y
CONFIG_BT_BLUESLEEP=y
-CONFIG_BT_TIBLUESLEEP=y
CONFIG_BT_WILINK=m
CONFIG_CFG80211=m
CONFIG_NL80211_TESTMODE=y
CONFIG_LIB80211=m
CONFIG_MAC80211=m
CONFIG_RFKILL=y
+CONFIG_RFKILL_GPIO=y
CONFIG_CAIF=y
CONFIG_NFC=y
CONFIG_PN544_NFC=y
@@ -191,7 +194,7 @@ CONFIG_AD525X_DPOT_I2C=y
CONFIG_APDS9802ALS=y
CONFIG_SENSORS_NCT1008=y
CONFIG_UID_STAT=y
-CONFIG_BCM4329_RFKILL=y
+# CONFIG_BCM4329_RFKILL is not set
CONFIG_TEGRA_CRYPTO_DEV=y
CONFIG_MAX1749_VIBRATOR=y
CONFIG_EEPROM_AT24=y
@@ -219,6 +222,7 @@ CONFIG_DM_CRYPT=y
CONFIG_DM_UEVENT=y
CONFIG_NETDEVICES=y
CONFIG_DUMMY=y
+CONFIG_TUN=y
# CONFIG_NETDEV_10000 is not set
CONFIG_BCM4329=m
CONFIG_BCM4329_FIRST_SCAN=y
@@ -229,6 +233,7 @@ CONFIG_BCM4329_HW_OOB=y
CONFIG_BCM4329_OOB_INTR_ONLY=y
CONFIG_BCM4329_CSCAN_ENABLE=y
CONFIG_BCMDHD=m
+CONFIG_DHD_ENABLE_P2P=y
CONFIG_BCMDHD_CFG80211=y
CONFIG_BCMDHD_WIFI_CONTROL_FUNC=y
CONFIG_BCMDHD_HW_OOB=y
@@ -292,6 +297,7 @@ CONFIG_SPI_TEGRA=y
CONFIG_SPI_SLAVE_TEGRA=y
CONFIG_DEBUG_GPIO=y
CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_RC5T583=y
CONFIG_POWER_SUPPLY=y
CONFIG_BATTERY_BQ20Z75=y
CONFIG_BATTERY_BQ27x00=y
@@ -307,16 +313,22 @@ CONFIG_MFD_TPS6586X=y
CONFIG_MFD_TPS65910=y
CONFIG_MFD_MAX77663=y
CONFIG_MFD_TPS6591X=y
+CONFIG_MFD_RC5T583=y
CONFIG_MFD_TPS80031=y
CONFIG_GPADC_TPS80031=y
CONFIG_MFD_RICOH583=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_VIRTUAL_CONSUMER=y
+CONFIG_REGULATOR_USERSPACE_CONSUMER=y
+CONFIG_REGULATOR_GPIO=y
+CONFIG_REGULATOR_MAX8973=y
CONFIG_REGULATOR_MAX77663=y
+CONFIG_REGULATOR_RC5T583=y
CONFIG_REGULATOR_TPS6586X=y
CONFIG_REGULATOR_TPS65910=y
CONFIG_REGULATOR_TPS62360=y
+CONFIG_REGULATOR_TPS6238X0=y
CONFIG_REGULATOR_TPS6591X=y
CONFIG_REGULATOR_TPS80031=y
CONFIG_REGULATOR_RICOH583=y
@@ -328,13 +340,16 @@ CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
# CONFIG_TEGRA_AVP is not set
# CONFIG_TEGRA_MEDIASERVER is not set
CONFIG_TEGRA_NVAVP=y
+CONFIG_TEGRA_NVAVP_AUDIO=y
CONFIG_VIDEO_OV5650=y
+CONFIG_VIDEO_OV5640=y
CONFIG_VIDEO_OV9726=y
CONFIG_VIDEO_OV2710=y
CONFIG_VIDEO_AR0832=y
CONFIG_TORCH_SSL3250A=y
CONFIG_TORCH_TPS61050=y
CONFIG_VIDEO_SH532U=y
+CONFIG_VIDEO_AD5816=y
CONFIG_USB_VIDEO_CLASS=y
# CONFIG_USB_GSPCA is not set
# CONFIG_RADIO_ADAPTERS is not set
@@ -381,7 +396,7 @@ CONFIG_USB_SERIAL_OPTION=y
CONFIG_USB_SERIAL_BASEBAND=m
CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_VBUS_DRAW=500
-CONFIG_USB_FSL_USB2=y
+CONFIG_USB_TEGRA=y
CONFIG_USB_G_ANDROID=y
CONFIG_USB_TEGRA_OTG=y
CONFIG_MMC=y
@@ -436,6 +451,7 @@ CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ISO8859_1=y
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_SECTION_MISMATCH=y
CONFIG_DEBUG_FS=y
CONFIG_LOCKUP_DETECTOR=y
# CONFIG_DETECT_HUNG_TASK is not set
diff --git a/arch/arm/configs/tegra3_defconfig b/arch/arm/configs/tegra3_defconfig
index 1243cb8ac51e..86d74c113a23 100644
--- a/arch/arm/configs/tegra3_defconfig
+++ b/arch/arm/configs/tegra3_defconfig
@@ -27,6 +27,9 @@ CONFIG_ARCH_TEGRA=y
CONFIG_GPIO_PCA953X=y
CONFIG_ARCH_TEGRA_3x_SOC=y
CONFIG_TEGRA_PCI=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCIEASPM=y
+CONFIG_PCIEASPM_POWERSAVE=y
CONFIG_MACH_CARDHU=y
CONFIG_MACH_TEGRA_ENTERPRISE=y
CONFIG_TEGRA_PWM=y
@@ -180,6 +183,7 @@ CONFIG_BT_HCIUART=y
CONFIG_BT_HCIUART_H4=y
CONFIG_BT_HCIUART_LL=y
CONFIG_BT_BLUESLEEP=y
+CONFIG_CFG80211=y
CONFIG_RFKILL=y
CONFIG_CAIF=y
CONFIG_NFC=y
@@ -192,7 +196,6 @@ CONFIG_AD525X_DPOT=y
CONFIG_AD525X_DPOT_I2C=y
CONFIG_ICS932S401=y
CONFIG_APDS9802ALS=y
-CONFIG_ISL29003=y
CONFIG_SENSORS_NCT1008=y
CONFIG_UID_STAT=y
CONFIG_BCM4329_RFKILL=y
@@ -290,8 +293,8 @@ CONFIG_SENSORS_TEGRA_TSENSOR=y
CONFIG_SENSORS_INA219=y
CONFIG_THERMAL=y
CONFIG_MFD_TPS6586X=y
-CONFIG_MFD_MAX8907C=y
CONFIG_MFD_TPS65910=y
+CONFIG_MFD_MAX8907C=y
CONFIG_MFD_MAX77663=y
CONFIG_MFD_TPS6591X=y
CONFIG_MFD_TPS80031=y
@@ -300,6 +303,7 @@ CONFIG_MFD_RICOH583=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_VIRTUAL_CONSUMER=y
+CONFIG_REGULATOR_USERSPACE_CONSUMER=y
CONFIG_REGULATOR_MAX8907C=y
CONFIG_REGULATOR_MAX77663=y
CONFIG_REGULATOR_TPS6586X=y
@@ -364,7 +368,7 @@ CONFIG_USB_SERIAL_OPTION=y
CONFIG_USB_SERIAL_BASEBAND=m
CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_VBUS_DRAW=500
-CONFIG_USB_FSL_USB2=y
+CONFIG_USB_TEGRA=y
CONFIG_USB_MASS_STORAGE=m
CONFIG_USB_TEGRA_OTG=y
CONFIG_MMC=y
@@ -383,6 +387,7 @@ CONFIG_RTC_DRV_TPS80031=y
CONFIG_RTC_DRV_RC5T583=y
CONFIG_STAGING=y
CONFIG_IIO=y
+CONFIG_SENSORS_ISL29028=y
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT2_FS_POSIX_ACL=y
diff --git a/arch/arm/configs/tegra_android_defconfig b/arch/arm/configs/tegra_android_defconfig
index b679b4096996..eb6abec87b70 100644
--- a/arch/arm/configs/tegra_android_defconfig
+++ b/arch/arm/configs/tegra_android_defconfig
@@ -170,6 +170,7 @@ CONFIG_BT_HCIUART_LL=y
CONFIG_BT_BLUESLEEP=y
CONFIG_CFG80211=y
CONFIG_RFKILL=y
+CONFIG_RFKILL_GPIO=y
# CONFIG_FIRMWARE_IN_KERNEL is not set
CONFIG_BLK_DEV_LOOP=y
CONFIG_MISC_DEVICES=y
@@ -178,7 +179,7 @@ CONFIG_AD525X_DPOT_I2C=y
CONFIG_APDS9802ALS=y
CONFIG_SENSORS_NCT1008=y
CONFIG_UID_STAT=y
-CONFIG_BCM4329_RFKILL=y
+# CONFIG_BCM4329_RFKILL is not set
CONFIG_TEGRA_CRYPTO_DEV=y
CONFIG_MAX1749_VIBRATOR=y
CONFIG_MPU_SENSORS_TIMERIRQ=y
@@ -200,6 +201,7 @@ CONFIG_DM_CRYPT=y
CONFIG_DM_UEVENT=y
CONFIG_NETDEVICES=y
CONFIG_DUMMY=y
+CONFIG_TUN=y
CONFIG_R8169=y
# CONFIG_NETDEV_10000 is not set
CONFIG_BCM4329=m
@@ -324,7 +326,7 @@ CONFIG_USB_SERIAL_PL2303=y
CONFIG_USB_SERIAL_OPTION=y
CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_VBUS_DRAW=500
-CONFIG_USB_FSL_USB2=y
+CONFIG_USB_TEGRA=y
CONFIG_USB_G_ANDROID=y
CONFIG_USB_TEGRA_OTG=y
CONFIG_MMC=y
@@ -380,6 +382,7 @@ CONFIG_TIMER_STATS=y
# CONFIG_DEBUG_PREEMPT is not set
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_VM=y
+CONFIG_FUNCTION_TRACER=y
CONFIG_CRYPTO_SHA256=y
CONFIG_CRYPTO_TWOFISH=y
# CONFIG_CRYPTO_ANSI_CPRNG is not set
diff --git a/arch/arm/configs/tegra_defconfig b/arch/arm/configs/tegra_defconfig
index 39a9d7314a12..e7b72881f054 100644
--- a/arch/arm/configs/tegra_defconfig
+++ b/arch/arm/configs/tegra_defconfig
@@ -271,6 +271,7 @@ CONFIG_BATTERY_BQ20Z75=y
CONFIG_CHARGER_GPIO=y
CONFIG_SENSORS_ADT7461=y
CONFIG_SENSORS_LM90=y
+CONFIG_THERMAL=y
CONFIG_MFD_TPS6586X=y
CONFIG_MFD_MAX8907C=y
CONFIG_REGULATOR=y
@@ -328,7 +329,7 @@ CONFIG_USB_SERIAL_PL2303=y
CONFIG_USB_SERIAL_OPTION=y
CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_VBUS_DRAW=500
-CONFIG_USB_FSL_USB2=y
+CONFIG_USB_TEGRA=y
CONFIG_USB_MASS_STORAGE=m
CONFIG_USB_TEGRA_OTG=y
CONFIG_MMC=y
diff --git a/arch/arm/configs/tegra_p1852_gnu_linux_defconfig b/arch/arm/configs/tegra_p1852_gnu_linux_defconfig
index 1afacd7b3cb9..7a1435a4024a 100644
--- a/arch/arm/configs/tegra_p1852_gnu_linux_defconfig
+++ b/arch/arm/configs/tegra_p1852_gnu_linux_defconfig
@@ -31,9 +31,12 @@ CONFIG_ARCH_TEGRA_3x_SOC=y
CONFIG_TEGRA_PCI=y
CONFIG_MACH_P1852=y
CONFIG_TEGRA_PWM=y
+CONFIG_TEGRA_P1852_TDM=y
# CONFIG_TEGRA_CPU_DVFS is not set
CONFIG_TEGRA_CLOCK_DEBUG_WRITE=y
# CONFIG_TEGRA_MC_EARLY_ACK is not set
+CONFIG_NON_ALIASED_COHERENT_MEM=y
+CONFIG_ARM_ERRATA_742230=y
CONFIG_ARM_ERRATA_743622=y
CONFIG_ARM_ERRATA_751472=y
CONFIG_ARM_ERRATA_752520=y
@@ -133,7 +136,6 @@ CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_VIRTUAL_CONSUMER=y
CONFIG_REGULATOR_TPS6591X=y
-CONFIG_REGULATOR_TPS6236X=y
CONFIG_MEDIA_SUPPORT=y
CONFIG_VIDEO_DEV=y
# CONFIG_TEGRA_AVP is not set
@@ -144,8 +146,6 @@ CONFIG_VIDEO_OUTPUT_CONTROL=y
CONFIG_FB=y
CONFIG_TEGRA_GRHOST=y
CONFIG_TEGRA_DC=y
-CONFIG_TEGRA_DC_EXTENSIONS=y
-CONFIG_NVMAP_SEARCH_GLOBAL_HANDLES=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
CONFIG_LCD_CLASS_DEVICE=y
CONFIG_BACKLIGHT_CLASS_DEVICE=y
@@ -170,6 +170,7 @@ CONFIG_MMC_EMBEDDED_SDIO=y
CONFIG_MMC_PARANOID_SD_INIT=y
# CONFIG_MMC_BLOCK_BOUNCE is not set
CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
+CONFIG_MMC_BKOPS=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_SDHCI_TEGRA=y
diff --git a/arch/arm/configs/tegra_p852_gnu_linux_defconfig b/arch/arm/configs/tegra_p852_gnu_linux_defconfig
index 7539158200c1..9f7e71711c4f 100644
--- a/arch/arm/configs/tegra_p852_gnu_linux_defconfig
+++ b/arch/arm/configs/tegra_p852_gnu_linux_defconfig
@@ -248,6 +248,7 @@ CONFIG_USB_SERIAL_GENERIC=y
CONFIG_USB_SERIAL_PL2303=y
CONFIG_USB_TEGRA_OTG=y
CONFIG_MMC=y
+CONFIG_MMC_BKOPS=y
CONFIG_MMC_UNSAFE_RESUME=y
# CONFIG_MMC_BLOCK_BOUNCE is not set
CONFIG_MMC_SDHCI=y
diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
index 7a21d0bf7134..19e3c8c77f01 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -75,6 +75,27 @@ static inline dma_addr_t virt_to_dma(struct device *dev, void *addr)
* Private support functions: these are not part of the API and are
* liable to change. Drivers must not use these.
*/
+#if defined(CONFIG_NON_ALIASED_COHERENT_MEM)
+static inline void __dma_single_cpu_to_dev(struct device *dev,
+ const void *kaddr, size_t size, enum dma_data_direction dir)
+{
+ extern void ___dma_single_cpu_to_dev(struct device *dev,
+ const void *, size_t, enum dma_data_direction);
+
+ if (!arch_is_coherent())
+ ___dma_single_cpu_to_dev(dev, kaddr, size, dir);
+}
+
+static inline void __dma_single_dev_to_cpu(struct device *dev,
+ const void *kaddr, size_t size, enum dma_data_direction dir)
+{
+ extern void ___dma_single_dev_to_cpu(struct device *dev,
+ const void *, size_t, enum dma_data_direction);
+
+ if (!arch_is_coherent())
+ ___dma_single_dev_to_cpu(dev, kaddr, size, dir);
+}
+#else
static inline void __dma_single_cpu_to_dev(const void *kaddr, size_t size,
enum dma_data_direction dir)
{
@@ -94,6 +115,7 @@ static inline void __dma_single_dev_to_cpu(const void *kaddr, size_t size,
if (!arch_is_coherent())
___dma_single_dev_to_cpu(kaddr, size, dir);
}
+#endif
static inline void __dma_page_cpu_to_dev(struct page *page, unsigned long off,
size_t size, enum dma_data_direction dir)
@@ -199,8 +221,12 @@ int dma_mmap_coherent(struct device *, struct vm_area_struct *,
extern void *dma_alloc_writecombine(struct device *, size_t, dma_addr_t *,
gfp_t);
+#if defined(CONFIG_NON_ALIASED_COHERENT_MEM)
+extern void dma_free_writecombine(struct device *, size_t, void *, dma_addr_t);
+#else
#define dma_free_writecombine(dev,size,cpu_addr,handle) \
dma_free_coherent(dev,size,cpu_addr,handle)
+#endif
int dma_mmap_writecombine(struct device *, struct vm_area_struct *,
void *, dma_addr_t, size_t);
@@ -421,7 +447,12 @@ static inline void dma_sync_single_range_for_cpu(struct device *dev,
if (!dmabounce_sync_for_cpu(dev, handle, offset, size, dir))
return;
+#if defined(CONFIG_NON_ALIASED_COHERENT_MEM)
+ __dma_single_dev_to_cpu(dev, dma_to_virt(dev, handle) + offset,
+ size, dir);
+#else
__dma_single_dev_to_cpu(dma_to_virt(dev, handle) + offset, size, dir);
+#endif
}
static inline void dma_sync_single_range_for_device(struct device *dev,
@@ -435,7 +466,12 @@ static inline void dma_sync_single_range_for_device(struct device *dev,
if (!dmabounce_sync_for_device(dev, handle, offset, size, dir))
return;
+#if defined(CONFIG_NON_ALIASED_COHERENT_MEM)
+ __dma_single_cpu_to_dev(dev, dma_to_virt(dev, handle) + offset,
+ size, dir);
+#else
__dma_single_cpu_to_dev(dma_to_virt(dev, handle) + offset, size, dir);
+#endif
}
static inline void dma_sync_single_for_cpu(struct device *dev,
diff --git a/arch/arm/include/asm/mach/map.h b/arch/arm/include/asm/mach/map.h
index d2fedb5aeb1f..3845215404dd 100644
--- a/arch/arm/include/asm/mach/map.h
+++ b/arch/arm/include/asm/mach/map.h
@@ -29,6 +29,8 @@ struct map_desc {
#define MT_MEMORY_NONCACHED 11
#define MT_MEMORY_DTCM 12
#define MT_MEMORY_ITCM 13
+#define MT_DMA_COHERENT 14
+#define MT_WC_COHERENT 15
#ifdef CONFIG_MMU
extern void iotable_init(struct map_desc *, int);
diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
index 25669795d80d..cf7c02042f60 100644
--- a/arch/arm/include/asm/memory.h
+++ b/arch/arm/include/asm/memory.h
@@ -88,6 +88,13 @@
#define CONSISTENT_END (0xffe00000UL)
#define CONSISTENT_BASE (CONSISTENT_END - CONSISTENT_DMA_SIZE)
+#ifndef CONSISTENT_WC_SIZE
+#define CONSISTENT_WC_SIZE SZ_2M
+#endif
+
+#define CONSISTENT_WC_END CONSISTENT_BASE
+#define CONSISTENT_WC_BASE (CONSISTENT_WC_END - CONSISTENT_WC_SIZE)
+
#else /* CONFIG_MMU */
/*
diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S
index e87f5f243012..714664b2b2ee 100644
--- a/arch/arm/kernel/sleep.S
+++ b/arch/arm/kernel/sleep.S
@@ -72,12 +72,14 @@ ENDPROC(cpu_suspend_abort)
* r3 = L1 section flags
*/
ENTRY(cpu_resume_mmu)
+#ifndef CONFIG_ARCH_HAS_SUSPEND_PAGETABLE
adr r4, cpu_resume_turn_mmu_on
mov r4, r4, lsr #20
orr r3, r3, r4, lsl #20
ldr r5, [r2, r4, lsl #2] @ save old mapping
str r3, [r2, r4, lsl #2] @ setup 1:1 mapping for mmu code
sub r2, r2, r1
+#endif
ldr r3, =cpu_resume_after_mmu
bic r1, r0, #CR_C @ ensure D-cache is disabled
b cpu_resume_turn_mmu_on
@@ -92,7 +94,9 @@ cpu_resume_turn_mmu_on:
mov pc, r3 @ jump to virtual address
ENDPROC(cpu_resume_turn_mmu_on)
cpu_resume_after_mmu:
+#ifndef CONFIG_ARCH_HAS_SUSPEND_PAGETABLE
str r5, [r2, r4, lsl #2] @ restore old mapping
+#endif
mcr p15, 0, r0, c1, c0, 0 @ turn on D-cache
mov r0, #0 @ return zero on success
ldmfd sp!, {r4 - r11, pc}
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index 0684e13f7e9c..722cba16101a 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -21,6 +21,10 @@ config ARCH_TEGRA_2x_SOC
select ARCH_SUPPORTS_MSI if TEGRA_PCI
select PCI_MSI if TEGRA_PCI
select CPA
+ select ARM_ERRATA_716044
+ select ARM_ERRATA_764369 if SMP
+ select ARCH_HAS_SUSPEND_PAGETABLE
+ select NVMAP_CACHE_MAINT_BY_SET_WAYS
help
Support for NVIDIA Tegra AP20 and T20 processors, based on the
ARM CortexA9MP CPU and the ARM PL310 L2 cache controller
@@ -44,8 +48,11 @@ config ARCH_TEGRA_3x_SOC
select ARCH_SUPPORTS_MSI if TEGRA_PCI
select PCI_MSI if TEGRA_PCI
select ARM_ERRATA_754322
+ select ARM_ERRATA_764369 if SMP
select TEGRA_LP2_ARM_TWD if HAVE_ARM_TWD && !TEGRA_RAIL_OFF_MULTIPLE_CPUS
select CPA
+ select ARCH_HAS_SUSPEND_PAGETABLE
+ select NVMAP_CACHE_MAINT_BY_SET_WAYS
help
Support for NVIDIA Tegra 3 family of SoCs, based upon the
ARM CortexA9MP CPU and the ARM PL310 L2 cache controller
@@ -255,6 +262,14 @@ config TEGRA_FIQ_DEBUGGER
help
Enables the FIQ serial debugger on Tegra
+config TEGRA_P1852_TDM
+ bool "Enable TDM mode for P1852 SKUs"
+ default n
+ depends on MACH_P1852
+ help
+ Enables TDM mode driver for P1852 SKUs. If this
+ is not defined then I2S mode is selected by default.
+
config TEGRA_CARDHU_DSI
bool "Support DSI panel on Cardhu"
depends on MACH_CARDHU
@@ -262,6 +277,13 @@ config TEGRA_CARDHU_DSI
help
Support for DSI Panel on Nvidia Cardhu
+config TEGRA_CARDHU_DUAL_DSI_PANEL
+ bool "Support Dual DSI panel on Cardhu"
+ default n
+ depends on TEGRA_CARDHU_DSI
+ help
+ Support for Dual DSI Panel on Nvidia Cardhu
+
config TEGRA_EMC_SCALING_ENABLE
bool "Enable scaling the memory frequency"
depends on TEGRA_SILICON_PLATFORM
@@ -280,7 +302,7 @@ config TEGRA_CORE_DVFS
config TEGRA_IOVMM_GART
bool "Enable I/O virtual memory manager for GART"
- depends on ARCH_TEGRA_2x_SOC
+ depends on ARCH_TEGRA_2x_SOC && !TEGRA_IOMMU_GART
default y
select TEGRA_IOVMM
help
@@ -291,7 +313,7 @@ config TEGRA_IOVMM_GART
config TEGRA_IOVMM_SMMU
bool "Enable I/O virtual memory manager for SMMU"
- depends on ARCH_TEGRA_3x_SOC
+ depends on ARCH_TEGRA_3x_SOC && !TEGRA_IOMMU_SMMU
default y
select TEGRA_IOVMM
help
@@ -308,6 +330,7 @@ config TEGRA_IOVMM_SMMU_SYSFS
Enables SMMU register access through /sys/devices/smmu/* files.
config TEGRA_IOVMM
+ depends on TEGRA_IOVMM_GART || TEGRA_IOVMM_SMMU
bool
config TEGRA_AVP_KERNEL_ON_MMU
@@ -319,7 +342,7 @@ config TEGRA_AVP_KERNEL_ON_MMU
config TEGRA_AVP_KERNEL_ON_SMMU
bool "Use SMMU to relocate AVP kernel"
- depends on TEGRA_IOVMM_SMMU
+ depends on TEGRA_IOVMM_SMMU || TEGRA_IOMMU_SMMU
default y
help
Use SMMU to relocate AVP kernel (nvrm_avp.bin).
@@ -331,6 +354,7 @@ config TEGRA_THERMAL_THROTTLE
bool "Enable throttling of CPU speed on overtemp"
depends on TEGRA_SILICON_PLATFORM
depends on CPU_FREQ
+ depends on THERMAL
default y
help
Also requires enabling a temperature sensor such as NCT1008.
@@ -410,6 +434,17 @@ config USB_HOTPLUG
bool "Enabling the USB hotplug"
default n
+config TEGRA_GADGET_BOOST_CPU_FREQ
+ int "Boost cpu frequency for tegra usb gadget (0-1300 mhz)"
+ range 0 1300
+ default 0
+ help
+ Devices need to boost frequency of CPU when they are connected
+ to host pc through usb cable for better performance. This value
+ is the amount of the frequency (in mhz) to be boosted. If it is
+ zero boosting frequency will not be enabled. This value will be
+ used only by usb gadget driver.
+
config TEGRA_DYNAMIC_PWRDET
bool "Enable dynamic activation of IO level auto-detection"
depends on TEGRA_SILICON_PLATFORM
@@ -451,11 +486,6 @@ config TEGRA_BB_XMM_POWER2
insert this LKM to initiate 2nd USB enumeration power sequence
- after modem software has been downloaded to flashless device.
-config TEGRA_THERMAL_SYSFS
- bool "Enable Thermal driver to use Thermal Sysfs infrastructure"
- depends on THERMAL
- default y
-
config TEGRA_PLLM_RESTRICTED
bool "Restrict PLLM usage as module clock source"
depends on !ARCH_TEGRA_2x_SOC
@@ -498,4 +528,13 @@ config TEGRA_PREPOWER_WIFI
default n
help
Pre-power up the on board WiFi chip
+
+config TEGRA_SKIN_THROTTLE
+ bool "Skin Temperature throttling"
+ depends on TEGRA_THERMAL_THROTTLE
+ depends on THERM_EST
+ default n
+ help
+ Enable throttling to control the temperature of the skin/case
+ of the device.
endif
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index 874527b41830..c2d78afc94b1 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -1,5 +1,7 @@
GCOV_PROFILE := y
+subdir-ccflags-y := -Werror
+
obj-y += ahb.o
obj-y += apbio.o
obj-y += common.o
@@ -8,7 +10,6 @@ obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += common-t2.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += common-t3.o
obj-y += io.o
obj-y += irq.o
-obj-$(CONFIG_TEGRA_GRHOST) += syncpt.o
obj-y += clock.o
obj-y += clock-common.o
obj-y += timer.o
@@ -28,7 +29,13 @@ obj-y += pm.o
obj-$(CONFIG_TEGRA_WDT_RECOVERY) += wdt-recovery.o
obj-$(CONFIG_PM_SLEEP) += pm-irq.o
obj-y += gic.o
+
+
obj-y += sleep.o
+
+plus_sec := $(call as-instr,.arch_extension sec,+sec)
+AFLAGS_sleep.o :=-Wa,-march=armv7-a$(plus_sec)
+
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += sleep-t2.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += sleep-t3.o
obj-y += fuse.o
@@ -39,6 +46,8 @@ obj-y += i2c_error_recovery.o
obj-y += mc.o
obj-$(CONFIG_TEGRA_STAT_MON) += tegra2_statmon.o
obj-$(CONFIG_USB_SUPPORT) += usb_phy.o
+obj-$(CONFIG_USB_SUPPORT) += tegra3_usb_phy.o
+obj-$(CONFIG_USB_SUPPORT) += tegra2_usb_phy.o
obj-$(CONFIG_FIQ) += fiq.o
obj-$(CONFIG_TEGRA_FIQ_DEBUGGER) += tegra_fiq_debugger.o
obj-$(CONFIG_TEGRA_PWM) += pwm.o
@@ -60,6 +69,7 @@ obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_emc.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra3_emc.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += wakeups-t2.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += wakeups-t3.o
+obj-y += wakeups.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += pm-t2.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += pm-t3.o
@@ -73,8 +83,12 @@ obj-y += reset.o
obj-$(CONFIG_TEGRA_SYSTEM_DMA) += dma.o
obj-$(CONFIG_CPU_FREQ) += cpu-tegra.o
ifeq ($(CONFIG_TEGRA_AUTO_HOTPLUG),y)
+ifeq ($(CONFIG_CPUQUIET_FRAMEWORK),y)
+obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += cpuquiet.o
+else
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += cpu-tegra3.o
endif
+endif
obj-$(CONFIG_TEGRA_PCI) += pcie.o
obj-$(CONFIG_USB_SUPPORT) += usb_phy.o
ifeq ($(CONFIG_CPU_IDLE),y)
diff --git a/arch/arm/mach-tegra/ahb.c b/arch/arm/mach-tegra/ahb.c
index b7f3fb5219bb..e27ba582fff6 100644
--- a/arch/arm/mach-tegra/ahb.c
+++ b/arch/arm/mach-tegra/ahb.c
@@ -87,9 +87,10 @@ static inline void gizmo_writel(unsigned long value, unsigned long offset)
writel(value, IO_TO_VIRT(TEGRA_AHB_GIZMO_BASE + offset));
}
+#ifdef CONFIG_PM
+
static u32 ahb_gizmo[29];
-#ifdef CONFIG_PM
int tegra_ahbgizmo_suspend(void)
{
ahb_gizmo[0] = gizmo_readl(AHB_ARBITRATION_DISABLE);
diff --git a/arch/arm/mach-tegra/apbio.c b/arch/arm/mach-tegra/apbio.c
index e227331c2f0f..5f3944993804 100644
--- a/arch/arm/mach-tegra/apbio.c
+++ b/arch/arm/mach-tegra/apbio.c
@@ -30,7 +30,7 @@
static DEFINE_MUTEX(tegra_apb_dma_lock);
-#ifdef CONFIG_TEGRA_SYSTEM_DMA
+#if defined(CONFIG_TEGRA_SYSTEM_DMA) && defined(CONFIG_ARCH_TEGRA_2x_SOC)
static struct tegra_dma_channel *tegra_apb_dma;
static u32 *tegra_apb_bb;
static dma_addr_t tegra_apb_bb_phys;
@@ -68,6 +68,8 @@ static inline u32 apb_readl(unsigned long offset)
req.source_wrap = 4;
req.req_sel = 0;
req.size = 4;
+ dma_sync_single_for_device(NULL, tegra_apb_bb_phys,
+ sizeof(u32), DMA_FROM_DEVICE);
INIT_COMPLETION(tegra_apb_wait);
@@ -81,6 +83,8 @@ static inline u32 apb_readl(unsigned long offset)
*(u32 *)tegra_apb_bb = 0;
}
+ dma_sync_single_for_cpu(NULL, tegra_apb_bb_phys,
+ sizeof(u32), DMA_FROM_DEVICE);
mutex_unlock(&tegra_apb_dma_lock);
return *((u32 *)tegra_apb_bb);
}
@@ -97,6 +101,8 @@ static inline void apb_writel(u32 value, unsigned long offset)
}
mutex_lock(&tegra_apb_dma_lock);
+ dma_sync_single_for_cpu(NULL, tegra_apb_bb_phys,
+ sizeof(u32), DMA_TO_DEVICE);
*((u32 *)tegra_apb_bb) = value;
req.complete = apb_dma_complete;
req.to_memory = 0;
@@ -111,6 +117,8 @@ static inline void apb_writel(u32 value, unsigned long offset)
INIT_COMPLETION(tegra_apb_wait);
+ dma_sync_single_for_device(NULL, tegra_apb_bb_phys,
+ sizeof(u32), DMA_TO_DEVICE);
tegra_dma_enqueue_req(tegra_apb_dma, &req);
ret = wait_for_completion_timeout(&tegra_apb_wait,
@@ -121,17 +129,6 @@ static inline void apb_writel(u32 value, unsigned long offset)
mutex_unlock(&tegra_apb_dma_lock);
}
-#else
-static inline u32 apb_readl(unsigned long offset)
-{
- return readl(IO_TO_VIRT(offset));
-}
-
-static inline void apb_writel(u32 value, unsigned long offset)
-{
- writel(value, IO_TO_VIRT(offset));
-}
-#endif
u32 tegra_apb_readl(unsigned long offset)
{
@@ -142,10 +139,11 @@ void tegra_apb_writel(u32 value, unsigned long offset)
{
apb_writel(value, offset);
}
+#endif
static int tegra_init_apb_dma(void)
{
-#ifdef CONFIG_TEGRA_SYSTEM_DMA
+#if defined(CONFIG_TEGRA_SYSTEM_DMA) && defined(CONFIG_ARCH_TEGRA_2x_SOC)
tegra_apb_dma = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT |
TEGRA_DMA_SHARED, "apbio");
if (!tegra_apb_dma) {
diff --git a/arch/arm/mach-tegra/apbio.h b/arch/arm/mach-tegra/apbio.h
index f0c87f06a209..121fda359e40 100644
--- a/arch/arm/mach-tegra/apbio.h
+++ b/arch/arm/mach-tegra/apbio.h
@@ -15,5 +15,17 @@
*
*/
+#if defined(CONFIG_TEGRA_SYSTEM_DMA) && defined(CONFIG_ARCH_TEGRA_2x_SOC)
u32 tegra_apb_readl(unsigned long offset);
void tegra_apb_writel(u32 value, unsigned long offset);
+#else
+static inline u32 tegra_apb_readl(unsigned long offset)
+{
+ return readl(IO_TO_VIRT(offset));
+}
+
+static inline void tegra_apb_writel(u32 value, unsigned long offset)
+{
+ writel(value, IO_TO_VIRT(offset));
+}
+#endif
diff --git a/arch/arm/mach-tegra/baseband-xmm-power.c b/arch/arm/mach-tegra/baseband-xmm-power.c
index 7659d4f8bbe5..36f5fc6611f9 100644
--- a/arch/arm/mach-tegra/baseband-xmm-power.c
+++ b/arch/arm/mach-tegra/baseband-xmm-power.c
@@ -31,7 +31,9 @@
#include <linux/usb.h>
#include <linux/pm_runtime.h>
#include <linux/suspend.h>
+#include <linux/pm_qos_params.h>
#include <mach/usb_phy.h>
+#include <linux/regulator/consumer.h>
#include "board.h"
#include "board-enterprise.h"
#include "devices.h"
@@ -89,12 +91,12 @@ static enum {
IPC_AP_WAKE_H,
} ipc_ap_wake_state;
-enum baseband_xmm_powerstate_t baseband_xmm_powerstate;
+static enum baseband_xmm_powerstate_t baseband_xmm_powerstate;
static struct workqueue_struct *workqueue;
static struct work_struct init1_work;
static struct work_struct init2_work;
static struct work_struct L2_resume_work;
-static struct baseband_power_platform_data *baseband_power_driver_data;
+static struct work_struct autopm_resume_work;
static bool register_hsic_device;
static struct wake_lock wakelock;
static struct usb_device *usbdev;
@@ -102,7 +104,6 @@ static bool CP_initiated_L2toL0;
static bool modem_power_on;
static int power_onoff;
static int reenable_autosuspend;
-static struct work_struct autopm_resume_work;
static bool wakeup_pending;
static bool modem_sleep_flag;
static spinlock_t xmm_lock;
@@ -110,10 +111,15 @@ static DEFINE_MUTEX(xmm_onoff_mutex);
static bool system_suspending;
static struct regulator *enterprise_hsic_reg;
static bool _hsic_reg_status;
+static struct pm_qos_request_list boost_cpu_freq_req;
+static struct delayed_work pm_qos_work;
+#define BOOST_CPU_FREQ_MIN 1500000
-static void baseband_xmm_power_L2_resume(void);
-static int baseband_xmm_power_driver_handle_resume(
- struct baseband_power_platform_data *data);
+/* driver specific data - same structure is used for flashless
+ * & flashed modem drivers i.e. baseband-xmm-power2.c
+ */
+struct xmm_power_data xmm_power_drv_data;
+EXPORT_SYMBOL(xmm_power_drv_data);
static int tegra_baseband_rail_on(void)
{
@@ -175,32 +181,64 @@ static int tegra_baseband_rail_off(void)
static int baseband_modem_power_on(struct baseband_power_platform_data *data)
{
/* set IPC_HSIC_ACTIVE active */
- gpio_set_value(baseband_power_driver_data->
- modem.xmm.ipc_hsic_active, 1);
+ gpio_set_value(data->modem.xmm.ipc_hsic_active, 1);
+
+ /* wait 20 ms */
+ mdelay(20);
/* reset / power on sequence */
- msleep(40);
+ mdelay(40);
gpio_set_value(data->modem.xmm.bb_rst, 1);
mdelay(1);
+
+ gpio_set_value(data->modem.xmm.bb_on, 1);
+ udelay(70);
+ gpio_set_value(data->modem.xmm.bb_on, 0);
+
+ return 0;
+}
+
+/* this function can sleep, do not call in atomic context */
+static int baseband_modem_power_on_async(
+ struct baseband_power_platform_data *data)
+{
+ /* set IPC_HSIC_ACTIVE active */
+ gpio_set_value(data->modem.xmm.ipc_hsic_active, 1);
+
+ /* wait 20 ms */
+ msleep(20);
+
+ /* reset / power on sequence */
+ msleep(40);
+ gpio_set_value(data->modem.xmm.bb_rst, 1);
+ usleep_range(1000, 2000);
+
gpio_set_value(data->modem.xmm.bb_on, 1);
udelay(70);
gpio_set_value(data->modem.xmm.bb_on, 0);
+ pr_debug("%s: pm qos request CPU 1.5GHz\n", __func__);
+ pm_qos_update_request(&boost_cpu_freq_req, (s32)BOOST_CPU_FREQ_MIN);
+ /* Device enumeration should happen in 1 sec however in any case
+ * we want to request it back to normal so schedule work to restore
+ * CPU freq after 2 seconds */
+ schedule_delayed_work(&pm_qos_work, msecs_to_jiffies(2000));
+
return 0;
}
-static int baseband_xmm_power_on(struct platform_device *device)
+static int xmm_power_on(struct platform_device *device)
{
- struct baseband_power_platform_data *data
- = (struct baseband_power_platform_data *)
+ struct baseband_power_platform_data *pdata =
device->dev.platform_data;
+ struct xmm_power_data *data = &xmm_power_drv_data;
int ret;
pr_debug("%s {\n", __func__);
/* check for platform data */
- if (!data) {
- pr_err("%s: !data\n", __func__);
+ if (!pdata) {
+ pr_err("%s: !pdata\n", __func__);
return -EINVAL;
}
if (baseband_xmm_powerstate != BBXMM_PS_UNINIT)
@@ -211,11 +249,7 @@ static int baseband_xmm_power_on(struct platform_device *device)
/* reset the state machine */
baseband_xmm_powerstate = BBXMM_PS_INIT;
modem_sleep_flag = false;
-
- if (modem_ver < XMM_MODEM_VER_1130)
- ipc_ap_wake_state = IPC_AP_WAKE_INIT1;
- else
- ipc_ap_wake_state = IPC_AP_WAKE_INIT2;
+ ipc_ap_wake_state = IPC_AP_WAKE_INIT2;
pr_debug("%s wake_st(%d) modem version %lu\n", __func__,
ipc_ap_wake_state, modem_ver);
@@ -228,24 +262,23 @@ static int baseband_xmm_power_on(struct platform_device *device)
pr_debug("%s: register usb host controller\n",
__func__);
modem_power_on = true;
- if (data->hsic_register)
- data->modem.xmm.hsic_device =
- data->hsic_register();
+ if (pdata->hsic_register)
+ data->hsic_device = pdata->hsic_register();
else
pr_err("%s: hsic_register is missing\n",
__func__);
register_hsic_device = false;
} else {
/* register usb host controller */
- if (data->hsic_register)
- data->modem.xmm.hsic_device =
- data->hsic_register();
+ if (pdata->hsic_register)
+ data->hsic_device = pdata->hsic_register();
/* turn on modem */
- pr_debug("%s call baseband_modem_power_on\n", __func__);
- baseband_modem_power_on(data);
+ pr_debug("%s call baseband_modem_power_on_async\n",
+ __func__);
+ baseband_modem_power_on_async(pdata);
}
}
- ret = enable_irq_wake(gpio_to_irq(data->modem.xmm.ipc_ap_wake));
+ ret = enable_irq_wake(gpio_to_irq(pdata->modem.xmm.ipc_ap_wake));
if (ret < 0)
pr_err("%s: enable_irq_wake error\n", __func__);
pr_debug("%s }\n", __func__);
@@ -253,9 +286,12 @@ static int baseband_xmm_power_on(struct platform_device *device)
return 0;
}
-static int baseband_xmm_power_off(struct platform_device *device)
+static int xmm_power_off(struct platform_device *device)
{
- struct baseband_power_platform_data *data;
+ struct baseband_power_platform_data *pdata =
+ device->dev.platform_data;
+ struct xmm_power_data *data = &xmm_power_drv_data;
+
int ret;
unsigned long flags;
@@ -268,35 +304,33 @@ static int baseband_xmm_power_off(struct platform_device *device)
pr_err("%s: !device\n", __func__);
return -EINVAL;
}
- data = (struct baseband_power_platform_data *)
- device->dev.platform_data;
- if (!data) {
- pr_err("%s: !data\n", __func__);
+ if (!pdata) {
+ pr_err("%s: !pdata\n", __func__);
return -EINVAL;
}
ipc_ap_wake_state = IPC_AP_WAKE_UNINIT;
- ret = disable_irq_wake(gpio_to_irq(data->modem.xmm.ipc_ap_wake));
+ ret = disable_irq_wake(gpio_to_irq(pdata->modem.xmm.ipc_ap_wake));
if (ret < 0)
pr_err("%s: disable_irq_wake error\n", __func__);
/* unregister usb host controller */
- if (data->hsic_unregister)
- data->hsic_unregister(data->modem.xmm.hsic_device);
+ if (pdata->hsic_unregister)
+ pdata->hsic_unregister(data->hsic_device);
else
pr_err("%s: hsic_unregister is missing\n", __func__);
/* set IPC_HSIC_ACTIVE low */
- gpio_set_value(baseband_power_driver_data->
- modem.xmm.ipc_hsic_active, 0);
+ gpio_set_value(pdata->modem.xmm.ipc_hsic_active, 0);
/* wait 20 ms */
- mdelay(20);
+ msleep(20);
/* drive bb_rst low */
- gpio_set_value(data->modem.xmm.bb_rst, 0);
- mdelay(1);
+ gpio_set_value(pdata->modem.xmm.bb_rst, 0);
+ /* sleep 1ms */
+ usleep_range(1000, 2000);
baseband_xmm_powerstate = BBXMM_PS_UNINIT;
modem_sleep_flag = false;
@@ -314,9 +348,8 @@ static int baseband_xmm_power_off(struct platform_device *device)
return 0;
}
-static ssize_t baseband_xmm_onoff(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t xmm_onoff(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
int pwr;
int size;
@@ -352,22 +385,88 @@ static ssize_t baseband_xmm_onoff(struct device *dev,
pr_debug("%s power_onoff=%d\n", __func__, power_onoff);
if (power_onoff == 0)
- baseband_xmm_power_off(device);
+ xmm_power_off(device);
else if (power_onoff == 1)
- baseband_xmm_power_on(device);
+ xmm_power_on(device);
mutex_unlock(&xmm_onoff_mutex);
return count;
}
+static void pm_qos_worker(struct work_struct *work)
+{
+ pr_debug("%s - pm qos CPU back to normal\n", __func__);
+ pm_qos_update_request(&boost_cpu_freq_req,
+ (s32)PM_QOS_CPU_FREQ_MIN_DEFAULT_VALUE);
+}
+
static DEVICE_ATTR(xmm_onoff, S_IRUSR | S_IWUSR | S_IRGRP,
- NULL, baseband_xmm_onoff);
+ NULL, xmm_onoff);
+
+/* Do the work for AP/CP initiated L2->L0 */
+static void xmm_power_l2_resume(void)
+{
+ struct baseband_power_platform_data *pdata = xmm_power_drv_data.pdata;
+ struct xmm_power_data *drv = &xmm_power_drv_data;
+ int value;
+ int delay = 1000; /* maxmum delay in msec */
+ unsigned long flags;
+ int ret, rcount = 0;
+
+ pr_debug("%s\n", __func__);
+
+ if (!pdata)
+ return;
+
+ /* claim the wakelock here to avoid any system suspend */
+ if (!wake_lock_active(&wakelock))
+ wake_lock_timeout(&wakelock, HZ*2);
+ modem_sleep_flag = false;
+ spin_lock_irqsave(&xmm_lock, flags);
+ wakeup_pending = false;
+ spin_unlock_irqrestore(&xmm_lock, flags);
+
+ if (CP_initiated_L2toL0) {
+ pr_info("CP L2->L0\n");
+ CP_initiated_L2toL0 = false;
+ queue_work(workqueue, &L2_resume_work);
+ } else {
+ /* set the slave wakeup request */
+ pr_info("AP/CP L2->L0\n");
+ value = gpio_get_value(pdata->modem.xmm.ipc_ap_wake);
+ if (value) {
+ drv->hostwake = 0;
+ /* wake bb */
+ gpio_set_value(pdata->modem.xmm.ipc_bb_wake, 1);
+retry:
+ /* wait for cp */
+ pr_debug("waiting for host wakeup from CP...\n");
+ ret = wait_event_interruptible_timeout(drv->bb_wait,
+ drv->hostwake == 1, msecs_to_jiffies(delay));
+ if (ret == 0) {
+ pr_info("!!AP L2->L0 Failed\n");
+ return;
+ }
+ if (ret == -ERESTARTSYS) {
+ if (rcount >= 5) {
+ pr_info("!!AP L2->L0 Failed\n");
+ return;
+ }
+ pr_debug("%s: caught signal\n", __func__);
+ rcount++;
+ goto retry;
+ }
+ pr_debug("Get gpio host wakeup low <-\n");
+ } else
+ pr_info("CP already ready\n");
+ }
+}
void baseband_xmm_set_power_status(unsigned int status)
{
- struct baseband_power_platform_data *data = baseband_power_driver_data;
+ struct baseband_power_platform_data *data = xmm_power_drv_data.pdata;
int value = 0;
unsigned long flags;
@@ -377,25 +476,24 @@ void baseband_xmm_set_power_status(unsigned int status)
switch (status) {
case BBXMM_PS_L0:
if (modem_sleep_flag) {
- pr_info("%s Resume from L3 without calling resume"
- "function\n", __func__);
- baseband_xmm_power_driver_handle_resume(data);
+ /* We dont have L3 state now, should be handled from L2
+ * xmm_power_driver_handle_resume(data);
+ */
}
pr_info("L0\n");
baseband_xmm_powerstate = status;
if (!wake_lock_active(&wakelock))
- wake_lock(&wakelock);
+ wake_lock_timeout(&wakelock, HZ*2);
value = gpio_get_value(data->modem.xmm.ipc_hsic_active);
pr_debug("before L0 ipc_hsic_active=%d\n", value);
if (!value) {
- pr_debug("before L0 gpio set ipc_hsic_active=1 ->\n");
+ pr_debug("L0 gpio set ipc_hsic_active=1 ->\n");
gpio_set_value(data->modem.xmm.ipc_hsic_active, 1);
}
if (modem_power_on) {
modem_power_on = false;
baseband_modem_power_on(data);
}
- pr_debug("gpio host active high->\n");
break;
case BBXMM_PS_L2:
pr_info("L2\n");
@@ -403,7 +501,8 @@ void baseband_xmm_set_power_status(unsigned int status)
spin_lock_irqsave(&xmm_lock, flags);
if (wakeup_pending) {
spin_unlock_irqrestore(&xmm_lock, flags);
- baseband_xmm_power_L2_resume();
+ pr_debug("%s: wakeup pending\n", __func__);
+ xmm_power_l2_resume();
} else {
spin_unlock_irqrestore(&xmm_lock, flags);
if (wake_lock_active(&wakelock))
@@ -411,34 +510,8 @@ void baseband_xmm_set_power_status(unsigned int status)
modem_sleep_flag = true;
}
break;
- case BBXMM_PS_L3:
- if (baseband_xmm_powerstate == BBXMM_PS_L2TOL0) {
- if (!data->modem.xmm.ipc_ap_wake) {
- spin_lock_irqsave(&xmm_lock, flags);
- wakeup_pending = true;
- spin_unlock_irqrestore(&xmm_lock, flags);
- pr_info("%s: L2 race condition-CP wakeup"
- " pending\n", __func__);
- }
- }
- pr_info("L3\n");
- /* system is going to suspend */
- if (baseband_xmm_powerstate == BBXMM_PS_L2)
- tegra_baseband_rail_off();
-
- baseband_xmm_powerstate = status;
- spin_lock_irqsave(&xmm_lock, flags);
- system_suspending = false;
- spin_unlock_irqrestore(&xmm_lock, flags);
- if (wake_lock_active(&wakelock)) {
- pr_info("%s: releasing wakelock before L3\n",
- __func__);
- wake_unlock(&wakelock);
- }
- gpio_set_value(data->modem.xmm.ipc_hsic_active, 0);
- pr_debug("gpio host active low->\n");
- break;
case BBXMM_PS_L2TOL0:
+ pr_debug("L2TOL0\n");
spin_lock_irqsave(&xmm_lock, flags);
system_suspending = false;
wakeup_pending = false;
@@ -447,16 +520,11 @@ void baseband_xmm_set_power_status(unsigned int status)
if (baseband_xmm_powerstate == BBXMM_PS_L2) {
baseband_xmm_powerstate = status;
pr_debug("BB XMM POWER STATE = %d\n", status);
- baseband_xmm_power_L2_resume();
+ xmm_power_l2_resume();
}
baseband_xmm_powerstate = status;
break;
- case BBXMM_PS_L3TOL0:
- /* poweron rail for L3 -> L0 (system resume) */
- pr_debug("L3 -> L0, turning on power rail.\n");
- tegra_baseband_rail_on();
- baseband_xmm_powerstate = status;
- break;
+
default:
baseband_xmm_powerstate = status;
break;
@@ -465,161 +533,153 @@ void baseband_xmm_set_power_status(unsigned int status)
}
EXPORT_SYMBOL_GPL(baseband_xmm_set_power_status);
-irqreturn_t baseband_xmm_power_ipc_ap_wake_irq(int irq, void *dev_id)
+irqreturn_t xmm_power_ipc_ap_wake_irq(int irq, void *dev_id)
{
+ struct baseband_power_platform_data *data = xmm_power_drv_data.pdata;
+ struct xmm_power_data *drv = &xmm_power_drv_data;
int value;
- struct baseband_power_platform_data *data = baseband_power_driver_data;
value = gpio_get_value(data->modem.xmm.ipc_ap_wake);
pr_debug("%s g(%d), wake_st(%d)\n", __func__, value, ipc_ap_wake_state);
- if (ipc_ap_wake_state < IPC_AP_WAKE_IRQ_READY) {
+ /* modem initialization/bootup part*/
+ if (unlikely(ipc_ap_wake_state < IPC_AP_WAKE_IRQ_READY)) {
pr_err("%s - spurious irq\n", __func__);
+ return IRQ_HANDLED;
} else if (ipc_ap_wake_state == IPC_AP_WAKE_IRQ_READY) {
if (!value) {
pr_debug("%s - IPC_AP_WAKE_INIT1"
- " - got falling edge\n",
- __func__);
+ " - got falling edge\n", __func__);
/* go to IPC_AP_WAKE_INIT1 state */
ipc_ap_wake_state = IPC_AP_WAKE_INIT1;
- /* queue work */
queue_work(workqueue, &init1_work);
- } else {
+ } else
pr_debug("%s - IPC_AP_WAKE_INIT1"
- " - wait for falling edge\n",
- __func__);
- }
+ " - wait for falling edge\n", __func__);
+ return IRQ_HANDLED;
} else if (ipc_ap_wake_state == IPC_AP_WAKE_INIT1) {
if (!value) {
pr_debug("%s - IPC_AP_WAKE_INIT2"
- " - wait for rising edge\n",
- __func__);
+ " - wait for rising edge\n", __func__);
} else {
pr_debug("%s - IPC_AP_WAKE_INIT2"
- " - got rising edge\n",
- __func__);
+ " - got rising edge\n", __func__);
/* go to IPC_AP_WAKE_INIT2 state */
ipc_ap_wake_state = IPC_AP_WAKE_INIT2;
- /* queue work */
queue_work(workqueue, &init2_work);
}
- } else {
- if (!value) {
- pr_debug("%s - falling\n", __func__);
- /* First check it a CP ack or CP wake */
- value = gpio_get_value
- (data->modem.xmm.ipc_bb_wake);
- if (value) {
- pr_debug("cp ack for bb_wake\n");
- ipc_ap_wake_state = IPC_AP_WAKE_L;
- return IRQ_HANDLED;
- }
- spin_lock(&xmm_lock);
- wakeup_pending = true;
- if (system_suspending) {
- spin_unlock(&xmm_lock);
- pr_info("Set wakeup_pending = 1 in system_"
- " suspending!!!\n");
- } else {
- if (baseband_xmm_powerstate ==
- BBXMM_PS_L3) {
- spin_unlock(&xmm_lock);
- pr_info(" CP L3 -> L0\n");
- } else if (baseband_xmm_powerstate ==
- BBXMM_PS_L2) {
- CP_initiated_L2toL0 = true;
- spin_unlock(&xmm_lock);
- baseband_xmm_set_power_status
- (BBXMM_PS_L2TOL0);
- } else {
- CP_initiated_L2toL0 = true;
- spin_unlock(&xmm_lock);
- }
- }
- /* save gpio state */
+ return IRQ_HANDLED;
+ }
+
+ /* modem wakeup part */
+ if (!value) {
+ pr_debug("%s - falling\n", __func__);
+ if (drv->hostwake == 0) {
+ /* AP L2 to L0 wakeup */
+ pr_debug("received wakeup ap l2->l0\n");
+ drv->hostwake = 1;
+ wake_up_interruptible(&drv->bb_wait);
+ }
+ /* First check it a CP ack or CP wake */
+ value = gpio_get_value(data->modem.xmm.ipc_bb_wake);
+ if (value) {
+ pr_debug("cp ack for bb_wake\n");
ipc_ap_wake_state = IPC_AP_WAKE_L;
+ return IRQ_HANDLED;
+ }
+
+ spin_lock(&xmm_lock);
+ wakeup_pending = true;
+ if (system_suspending) {
+ spin_unlock(&xmm_lock);
+ pr_info("Set wakeup_pending = 1 in system_"
+ " suspending!!!\n");
} else {
- pr_debug("%s - rising\n", __func__);
- value = gpio_get_value
- (data->modem.xmm.ipc_hsic_active);
- if (!value) {
- pr_info("host active low: ignore request\n");
- ipc_ap_wake_state = IPC_AP_WAKE_H;
- return IRQ_HANDLED;
- }
- value = gpio_get_value
- (data->modem.xmm.ipc_bb_wake);
- if (value) {
- /* Clear the slave wakeup request */
- gpio_set_value
- (data->modem.xmm.ipc_bb_wake, 0);
- pr_debug("gpio slave wakeup done ->\n");
- }
- if (reenable_autosuspend && usbdev) {
- reenable_autosuspend = false;
- queue_work(workqueue,
- &autopm_resume_work);
+ if (baseband_xmm_powerstate == BBXMM_PS_L2) {
+ CP_initiated_L2toL0 = true;
+ spin_unlock(&xmm_lock);
+ baseband_xmm_set_power_status(BBXMM_PS_L2TOL0);
+ } else {
+ CP_initiated_L2toL0 = true;
+ spin_unlock(&xmm_lock);
}
- modem_sleep_flag = false;
- baseband_xmm_set_power_status(
- BBXMM_PS_L0);
- /* save gpio state */
+ }
+ /* save gpio state */
+ ipc_ap_wake_state = IPC_AP_WAKE_L;
+ } else {
+ pr_debug("%s - rising\n", __func__);
+ value = gpio_get_value(data->modem.xmm.ipc_hsic_active);
+ if (!value) {
+ pr_info("host active low: ignore request\n");
ipc_ap_wake_state = IPC_AP_WAKE_H;
+ return IRQ_HANDLED;
+ }
+ value = gpio_get_value(data->modem.xmm.ipc_bb_wake);
+ if (value) {
+ /* Clear the slave wakeup request */
+ gpio_set_value(data->modem.xmm.ipc_bb_wake, 0);
+ pr_debug("gpio slave wakeup done ->\n");
+ }
+ if (reenable_autosuspend && usbdev) {
+ reenable_autosuspend = false;
+ queue_work(workqueue, &autopm_resume_work);
}
+ modem_sleep_flag = false;
+ baseband_xmm_set_power_status(BBXMM_PS_L0);
+ /* save gpio state */
+ ipc_ap_wake_state = IPC_AP_WAKE_H;
}
return IRQ_HANDLED;
}
-EXPORT_SYMBOL(baseband_xmm_power_ipc_ap_wake_irq);
+EXPORT_SYMBOL(xmm_power_ipc_ap_wake_irq);
-static void baseband_xmm_power_init1_work(struct work_struct *work)
+static void xmm_power_init1_work(struct work_struct *work)
{
+ struct baseband_power_platform_data *pdata = xmm_power_drv_data.pdata;
int value;
pr_debug("%s {\n", __func__);
/* check if IPC_HSIC_ACTIVE high */
- value = gpio_get_value(baseband_power_driver_data->
- modem.xmm.ipc_hsic_active);
+ value = gpio_get_value(pdata->modem.xmm.ipc_hsic_active);
if (value != 1) {
pr_err("%s - expected IPC_HSIC_ACTIVE high!\n", __func__);
return;
}
/* wait 100 ms */
- mdelay(100);
+ msleep(100);
/* set IPC_HSIC_ACTIVE low */
- gpio_set_value(baseband_power_driver_data->
- modem.xmm.ipc_hsic_active, 0);
+ gpio_set_value(pdata->modem.xmm.ipc_hsic_active, 0);
/* wait 10 ms */
- mdelay(10);
+ usleep_range(10000, 11000);
/* set IPC_HSIC_ACTIVE high */
- gpio_set_value(baseband_power_driver_data->
- modem.xmm.ipc_hsic_active, 1);
+ gpio_set_value(pdata->modem.xmm.ipc_hsic_active, 1);
/* wait 20 ms */
- mdelay(20);
+ msleep(20);
pr_debug("%s }\n", __func__);
}
-static void baseband_xmm_power_init2_work(struct work_struct *work)
+static void xmm_power_init2_work(struct work_struct *work)
{
- struct baseband_power_platform_data *data = baseband_power_driver_data;
+ struct baseband_power_platform_data *pdata = xmm_power_drv_data.pdata;
pr_debug("%s\n", __func__);
/* check input */
- if (!data)
+ if (!pdata)
return;
/* register usb host controller only once */
if (register_hsic_device) {
- if (data->hsic_register)
- data->modem.xmm.hsic_device = data->hsic_register();
+ if (pdata->hsic_register)
+ xmm_power_drv_data.hsic_device = pdata->hsic_register();
else
pr_err("%s: hsic_register is missing\n", __func__);
register_hsic_device = false;
@@ -627,7 +687,7 @@ static void baseband_xmm_power_init2_work(struct work_struct *work)
}
-static void baseband_xmm_power_autopm_resume(struct work_struct *work)
+static void xmm_power_autopm_resume(struct work_struct *work)
{
struct usb_interface *intf;
@@ -646,57 +706,8 @@ static void baseband_xmm_power_autopm_resume(struct work_struct *work)
}
-/* Do the work for AP/CP initiated L2->L0 */
-static void baseband_xmm_power_L2_resume(void)
-{
- struct baseband_power_platform_data *data = baseband_power_driver_data;
- int value;
- int delay = 10000; /* maxmum delay in msec */
- unsigned long flags;
-
- pr_debug("%s\n", __func__);
-
- if (!baseband_power_driver_data)
- return;
-
- /* claim the wakelock here to avoid any system suspend */
- if (!wake_lock_active(&wakelock))
- wake_lock(&wakelock);
- modem_sleep_flag = false;
- spin_lock_irqsave(&xmm_lock, flags);
- wakeup_pending = false;
- spin_unlock_irqrestore(&xmm_lock, flags);
-
- if (CP_initiated_L2toL0) {
- pr_info("CP L2->L0\n");
- CP_initiated_L2toL0 = false;
- queue_work(workqueue, &L2_resume_work);
- } else {
- /* set the slave wakeup request */
- pr_info("AP L2->L0\n");
- value = gpio_get_value(data->modem.xmm.ipc_ap_wake);
- if (value) {
- pr_debug("waiting for host wakeup from CP...\n");
- /* wake bb */
- gpio_set_value(data->modem.xmm.ipc_bb_wake, 1);
- do {
- mdelay(1);
- value = gpio_get_value(
- data->modem.xmm.ipc_ap_wake);
- delay--;
- } while ((value) && (delay));
- if (delay)
- pr_debug("gpio host wakeup low <-\n");
- else
- pr_info("!!AP L2->L0 Failed\n");
- } else {
- pr_info("CP already ready\n");
- }
- }
-}
-
/* Do the work for CP initiated L2->L0 */
-static void baseband_xmm_power_L2_resume_work(struct work_struct *work)
+static void xmm_power_l2_resume_work(struct work_struct *work)
{
struct usb_interface *intf;
@@ -713,120 +724,78 @@ static void baseband_xmm_power_L2_resume_work(struct work_struct *work)
pr_debug("} %s\n", __func__);
}
-static void baseband_xmm_power_reset_on(void)
+static void xmm_power_reset_on(struct baseband_power_platform_data *pdata)
{
/* reset / power on sequence */
- gpio_set_value(baseband_power_driver_data->modem.xmm.bb_rst, 0);
+ gpio_set_value(pdata->modem.xmm.bb_rst, 0);
msleep(40);
- gpio_set_value(baseband_power_driver_data->modem.xmm.bb_rst, 1);
- mdelay(1);
- gpio_set_value(baseband_power_driver_data->modem.xmm.bb_on, 1);
+ gpio_set_value(pdata->modem.xmm.bb_rst, 1);
+ usleep_range(1000, 2000);
+ gpio_set_value(pdata->modem.xmm.bb_on, 1);
udelay(70);
- gpio_set_value(baseband_power_driver_data->modem.xmm.bb_on, 0);
+ gpio_set_value(pdata->modem.xmm.bb_on, 0);
}
-static struct baseband_xmm_power_work_t *baseband_xmm_power_work;
-static void baseband_xmm_power_work_func(struct work_struct *work)
+static void xmm_power_work_func(struct work_struct *work)
{
- struct baseband_xmm_power_work_t *bbxmm_work
- = (struct baseband_xmm_power_work_t *) work;
+ struct xmm_power_data *data =
+ container_of(work, struct xmm_power_data, work);
+ struct baseband_power_platform_data *pdata = data->pdata;
pr_debug("%s\n", __func__);
- switch (bbxmm_work->state) {
+ switch (data->state) {
case BBXMM_WORK_UNINIT:
pr_debug("BBXMM_WORK_UNINIT\n");
break;
case BBXMM_WORK_INIT:
pr_debug("BBXMM_WORK_INIT\n");
/* go to next state */
- bbxmm_work->state = (modem_flash && !modem_pm)
+ data->state = (modem_flash && !modem_pm)
? BBXMM_WORK_INIT_FLASH_STEP1
: (modem_flash && modem_pm)
? BBXMM_WORK_INIT_FLASH_PM_STEP1
: (!modem_flash && modem_pm)
? BBXMM_WORK_INIT_FLASHLESS_PM_STEP1
: BBXMM_WORK_UNINIT;
- pr_debug("Go to next state %d\n", bbxmm_work->state);
+ pr_debug("Go to next state %d\n", data->state);
queue_work(workqueue, work);
break;
case BBXMM_WORK_INIT_FLASH_STEP1:
pr_debug("BBXMM_WORK_INIT_FLASH_STEP1\n");
/* register usb host controller */
pr_debug("%s: register usb host controller\n", __func__);
- if (baseband_power_driver_data->hsic_register)
- baseband_power_driver_data->modem.xmm.hsic_device =
- baseband_power_driver_data->hsic_register();
+ if (pdata->hsic_register)
+ data->hsic_device = pdata->hsic_register();
else
pr_err("%s: hsic_register is missing\n", __func__);
break;
case BBXMM_WORK_INIT_FLASH_PM_STEP1:
pr_debug("BBXMM_WORK_INIT_FLASH_PM_STEP1\n");
- /* [modem ver >= 1130] start with IPC_HSIC_ACTIVE low */
- if (modem_ver >= XMM_MODEM_VER_1130) {
- pr_debug("%s: ver > 1130:"
- " ipc_hsic_active -> 0\n", __func__);
- gpio_set_value(baseband_power_driver_data->
- modem.xmm.ipc_hsic_active, 0);
- }
+ pr_debug("%s: ipc_hsic_active -> 0\n", __func__);
+ gpio_set_value(pdata->modem.xmm.ipc_hsic_active, 1);
/* reset / power on sequence */
- baseband_xmm_power_reset_on();
+ xmm_power_reset_on(pdata);
/* set power status as on */
power_onoff = 1;
- /* optional delay
- * 0 = flashless
- * ==> causes next step to enumerate modem boot rom
- * (058b / 0041)
- * some delay > boot rom timeout
- * ==> causes next step to enumerate modem software
- * (1519 / 0020)
- * (requires modem to be flash version, not flashless
- * version)
+ gpio_set_value(pdata->modem.xmm.ipc_hsic_active, 0);
+
+ /* expecting init2 performs register hsic to enumerate modem
+ * software directly.
*/
- if (enum_delay_ms)
- mdelay(enum_delay_ms);
- /* register usb host controller */
- pr_debug("%s: register usb host controller\n", __func__);
- if (baseband_power_driver_data->hsic_register)
- baseband_power_driver_data->modem.xmm.hsic_device =
- baseband_power_driver_data->hsic_register();
- else
- pr_err("%s: hsic_register is missing\n", __func__);
- /* go to next state */
- bbxmm_work->state = (modem_ver < XMM_MODEM_VER_1130)
- ? BBXMM_WORK_INIT_FLASH_PM_VER_LT_1130_STEP1
- : BBXMM_WORK_INIT_FLASH_PM_VER_GE_1130_STEP1;
- queue_work(workqueue, work);
- pr_debug("Go to next state %d\n", bbxmm_work->state);
- break;
- case BBXMM_WORK_INIT_FLASH_PM_VER_LT_1130_STEP1:
- pr_debug("BBXMM_WORK_INIT_FLASH_PM_VER_LT_1130_STEP1\n");
- break;
- case BBXMM_WORK_INIT_FLASH_PM_VER_GE_1130_STEP1:
- pr_debug("BBXMM_WORK_INIT_FLASH_PM_VER_GE_1130_STEP1\n");
break;
+
case BBXMM_WORK_INIT_FLASHLESS_PM_STEP1:
pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_STEP1\n");
- /* go to next state */
- bbxmm_work->state = (modem_ver < XMM_MODEM_VER_1130)
- ? BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_WAIT_IRQ
- : BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP1;
- queue_work(workqueue, work);
- break;
- case BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_STEP1:
- pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_STEP1\n");
- break;
- case BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP1:
- pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP1\n");
+ pr_info("%s: flashless is not supported here\n", __func__);
break;
default:
break;
}
-
}
-static void baseband_xmm_device_add_handler(struct usb_device *udev)
+static void xmm_device_add_handler(struct usb_device *udev)
{
struct usb_interface *intf = usb_ifnum_to_if(udev, 0);
const struct usb_device_id *id;
@@ -846,7 +815,7 @@ static void baseband_xmm_device_add_handler(struct usb_device *udev)
}
}
-static void baseband_xmm_device_remove_handler(struct usb_device *udev)
+static void xmm_device_remove_handler(struct usb_device *udev)
{
if (usbdev == udev) {
pr_info("Remove device %d <%s %s>\n", udev->devnum,
@@ -861,10 +830,10 @@ static int usb_xmm_notify(struct notifier_block *self, unsigned long action,
{
switch (action) {
case USB_DEVICE_ADD:
- baseband_xmm_device_add_handler(blob);
+ xmm_device_add_handler(blob);
break;
case USB_DEVICE_REMOVE:
- baseband_xmm_device_remove_handler(blob);
+ xmm_device_remove_handler(blob);
break;
}
@@ -876,13 +845,13 @@ static struct notifier_block usb_xmm_nb = {
.notifier_call = usb_xmm_notify,
};
-static int baseband_xmm_power_pm_notifier_event(struct notifier_block *this,
+static int xmm_power_pm_notifier_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
- struct baseband_power_platform_data *data = baseband_power_driver_data;
+ struct baseband_power_platform_data *pdata = xmm_power_drv_data.pdata;
unsigned long flags;
- if (!data)
+ if (!pdata)
return NOTIFY_DONE;
pr_debug("%s: event %ld\n", __func__, event);
@@ -914,11 +883,9 @@ static int baseband_xmm_power_pm_notifier_event(struct notifier_block *this,
(baseband_xmm_powerstate == BBXMM_PS_L2)) {
wakeup_pending = false;
spin_unlock_irqrestore(&xmm_lock, flags);
- pr_info("%s : Service Pending CP wakeup\n",
- __func__);
+ pr_info("%s : Service Pending CP wakeup\n", __func__);
CP_initiated_L2toL0 = true;
- baseband_xmm_set_power_status
- (BBXMM_PS_L2TOL0);
+ baseband_xmm_set_power_status(BBXMM_PS_L2TOL0);
return NOTIFY_OK;
}
wakeup_pending = false;
@@ -928,16 +895,14 @@ static int baseband_xmm_power_pm_notifier_event(struct notifier_block *this,
return NOTIFY_DONE;
}
-static struct notifier_block baseband_xmm_power_pm_notifier = {
- .notifier_call = baseband_xmm_power_pm_notifier_event,
+static struct notifier_block xmm_power_pm_notifier = {
+ .notifier_call = xmm_power_pm_notifier_event,
};
-static int baseband_xmm_power_driver_probe(struct platform_device *device)
+static int xmm_power_driver_probe(struct platform_device *device)
{
- struct baseband_power_platform_data *data
- = (struct baseband_power_platform_data *)
- device->dev.platform_data;
+ struct baseband_power_platform_data *pdata = device->dev.platform_data;
struct device *dev = &device->dev;
unsigned long flags;
int err;
@@ -946,17 +911,21 @@ static int baseband_xmm_power_driver_probe(struct platform_device *device)
pr_debug("[XMM] enum_delay_ms=%ld\n", enum_delay_ms);
/* check for platform data */
- if (!data)
+ if (!pdata)
return -ENODEV;
/* check if supported modem */
- if (data->baseband_type != BASEBAND_XMM) {
+ if (pdata->baseband_type != BASEBAND_XMM) {
pr_err("unsuppported modem\n");
return -ENODEV;
}
/* save platform data */
- baseband_power_driver_data = data;
+ xmm_power_drv_data.pdata = pdata;
+
+ /* init wait queue */
+ xmm_power_drv_data.hostwake = 1;
+ init_waitqueue_head(&xmm_power_drv_data.bb_wait);
/* create device file */
err = device_create_file(dev, &dev_attr_xmm_onoff);
@@ -971,20 +940,14 @@ static int baseband_xmm_power_driver_probe(struct platform_device *device)
/* init spin lock */
spin_lock_init(&xmm_lock);
/* request baseband gpio(s) */
- tegra_baseband_gpios[0].gpio = baseband_power_driver_data
- ->modem.xmm.bb_rst;
- tegra_baseband_gpios[1].gpio = baseband_power_driver_data
- ->modem.xmm.bb_on;
- tegra_baseband_gpios[2].gpio = baseband_power_driver_data
- ->modem.xmm.ipc_bb_wake;
- tegra_baseband_gpios[3].gpio = baseband_power_driver_data
- ->modem.xmm.ipc_ap_wake;
- tegra_baseband_gpios[4].gpio = baseband_power_driver_data
- ->modem.xmm.ipc_hsic_active;
- tegra_baseband_gpios[5].gpio = baseband_power_driver_data
- ->modem.xmm.ipc_hsic_sus_req;
+ tegra_baseband_gpios[0].gpio = pdata->modem.xmm.bb_rst;
+ tegra_baseband_gpios[1].gpio = pdata->modem.xmm.bb_on;
+ tegra_baseband_gpios[2].gpio = pdata->modem.xmm.ipc_bb_wake;
+ tegra_baseband_gpios[3].gpio = pdata->modem.xmm.ipc_ap_wake;
+ tegra_baseband_gpios[4].gpio = pdata->modem.xmm.ipc_hsic_active;
+ tegra_baseband_gpios[5].gpio = pdata->modem.xmm.ipc_hsic_sus_req;
err = gpio_request_array(tegra_baseband_gpios,
- ARRAY_SIZE(tegra_baseband_gpios));
+ ARRAY_SIZE(tegra_baseband_gpios));
if (err < 0) {
pr_err("%s - request gpio(s) failed\n", __func__);
return -ENODEV;
@@ -995,52 +958,41 @@ static int baseband_xmm_power_driver_probe(struct platform_device *device)
pr_debug("%s: request_irq IPC_AP_WAKE_IRQ\n", __func__);
ipc_ap_wake_state = IPC_AP_WAKE_UNINIT;
err = request_threaded_irq(
- gpio_to_irq(data->modem.xmm.ipc_ap_wake),
- NULL,
- baseband_xmm_power_ipc_ap_wake_irq,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "IPC_AP_WAKE_IRQ",
- NULL);
+ gpio_to_irq(pdata->modem.xmm.ipc_ap_wake),
+ NULL, xmm_power_ipc_ap_wake_irq,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ "IPC_AP_WAKE_IRQ", NULL);
if (err < 0) {
pr_err("%s - request irq IPC_AP_WAKE_IRQ failed\n",
__func__);
return err;
}
- err = enable_irq_wake(gpio_to_irq(data->modem.xmm.ipc_ap_wake));
+ err = enable_irq_wake(gpio_to_irq(
+ pdata->modem.xmm.ipc_ap_wake));
if (err < 0)
pr_err("%s: enable_irq_wake error\n", __func__);
- ipc_ap_wake_state = IPC_AP_WAKE_IRQ_READY;
- if (modem_ver >= XMM_MODEM_VER_1130) {
- pr_debug("%s: ver > 1130: AP_WAKE_INIT1\n", __func__);
- /* ver 1130 or later starts in INIT1 state */
- ipc_ap_wake_state = IPC_AP_WAKE_INIT1;
- }
+
+ pr_debug("%s: AP_WAKE_INIT1\n", __func__);
+ /* ver 1130 or later starts in INIT1 state */
+ ipc_ap_wake_state = IPC_AP_WAKE_INIT1;
}
/* init work queue */
- workqueue = create_singlethread_workqueue
- ("baseband_xmm_power_workqueue");
+ workqueue = create_singlethread_workqueue("xmm_power_wq");
if (!workqueue) {
pr_err("cannot create workqueue\n");
- return -1;
+ return -ENOMEM;
}
- baseband_xmm_power_work = (struct baseband_xmm_power_work_t *)
- kmalloc(sizeof(struct baseband_xmm_power_work_t), GFP_KERNEL);
- if (!baseband_xmm_power_work) {
- pr_err("cannot allocate baseband_xmm_power_work\n");
- return -1;
- }
- INIT_WORK((struct work_struct *) baseband_xmm_power_work,
- baseband_xmm_power_work_func);
- baseband_xmm_power_work->state = BBXMM_WORK_INIT;
- queue_work(workqueue,
- (struct work_struct *) baseband_xmm_power_work);
+
+ INIT_WORK(&xmm_power_drv_data.work, xmm_power_work_func);
+ xmm_power_drv_data.state = BBXMM_WORK_INIT;
+ queue_work(workqueue, &xmm_power_drv_data.work);
/* init work objects */
- INIT_WORK(&init1_work, baseband_xmm_power_init1_work);
- INIT_WORK(&init2_work, baseband_xmm_power_init2_work);
- INIT_WORK(&L2_resume_work, baseband_xmm_power_L2_resume_work);
- INIT_WORK(&autopm_resume_work, baseband_xmm_power_autopm_resume);
+ INIT_WORK(&init1_work, xmm_power_init1_work);
+ INIT_WORK(&init2_work, xmm_power_init2_work);
+ INIT_WORK(&L2_resume_work, xmm_power_l2_resume_work);
+ INIT_WORK(&autopm_resume_work, xmm_power_autopm_resume);
/* init state variables */
register_hsic_device = true;
@@ -1052,36 +1004,30 @@ static int baseband_xmm_power_driver_probe(struct platform_device *device)
spin_unlock_irqrestore(&xmm_lock, flags);
usb_register_notify(&usb_xmm_nb);
- register_pm_notifier(&baseband_xmm_power_pm_notifier);
+ register_pm_notifier(&xmm_power_pm_notifier);
pr_debug("%s }\n", __func__);
return 0;
}
-static int baseband_xmm_power_driver_remove(struct platform_device *device)
+static int xmm_power_driver_remove(struct platform_device *device)
{
- struct baseband_power_platform_data *data
- = (struct baseband_power_platform_data *)
- device->dev.platform_data;
+ struct baseband_power_platform_data *pdata = device->dev.platform_data;
+ struct xmm_power_data *data = &xmm_power_drv_data;
struct device *dev = &device->dev;
pr_debug("%s\n", __func__);
/* check for platform data */
- if (!data)
+ if (!pdata)
return 0;
- unregister_pm_notifier(&baseband_xmm_power_pm_notifier);
+ unregister_pm_notifier(&xmm_power_pm_notifier);
usb_unregister_notify(&usb_xmm_nb);
- /* free work structure */
- kfree(baseband_xmm_power_work);
- baseband_xmm_power_work = (struct baseband_xmm_power_work_t *) 0;
-
/* free baseband irq(s) */
if (modem_flash && modem_pm) {
- free_irq(gpio_to_irq(baseband_power_driver_data
- ->modem.xmm.ipc_ap_wake), NULL);
+ free_irq(gpio_to_irq(pdata->modem.xmm.ipc_ap_wake), NULL);
}
/* free baseband gpio(s) */
@@ -1095,86 +1041,48 @@ static int baseband_xmm_power_driver_remove(struct platform_device *device)
device_remove_file(dev, &dev_attr_xmm_onoff);
/* unregister usb host controller */
- if (data->hsic_unregister)
- data->hsic_unregister(data->modem.xmm.hsic_device);
+ if (pdata->hsic_unregister)
+ pdata->hsic_unregister(data->hsic_device);
else
pr_err("%s: hsic_unregister is missing\n", __func__);
return 0;
}
-static int baseband_xmm_power_driver_handle_resume(
- struct baseband_power_platform_data *data)
+#ifdef CONFIG_PM
+static int xmm_power_driver_suspend(struct device *dev)
{
- int value;
- int delay = 1000; /* maxmum delay in msec */
- unsigned long flags;
-
pr_debug("%s\n", __func__);
- if (!data)
- return 0;
/* check if modem is on */
if (power_onoff == 0) {
pr_debug("%s - flight mode - nop\n", __func__);
return 0;
}
-
- modem_sleep_flag = false;
- spin_lock_irqsave(&xmm_lock, flags);
- wakeup_pending = false;
- spin_unlock_irqrestore(&xmm_lock, flags);
-
- /* L3->L0 */
- baseband_xmm_set_power_status(BBXMM_PS_L3TOL0);
- value = gpio_get_value(data->modem.xmm.ipc_ap_wake);
- if (value) {
- pr_info("AP L3 -> L0\n");
- pr_debug("waiting for host wakeup...\n");
- /* wake bb */
- gpio_set_value(data->modem.xmm.ipc_bb_wake, 1);
- do {
- mdelay(1);
- value = gpio_get_value(
- data->modem.xmm.ipc_ap_wake);
- delay--;
- } while ((value) && (delay));
- if (delay)
- pr_debug("gpio host wakeup low <-\n");
- else
- pr_info("!!AP L3->L0 Failed\n");
-
- } else {
- pr_info("CP L3 -> L0\n");
- }
- reenable_autosuspend = true;
-
+ /* PMC is driving hsic bus
+ * tegra_baseband_rail_off();
+ */
return 0;
-
}
-
-#ifdef CONFIG_PM
-static int baseband_xmm_power_driver_suspend(struct device *dev)
+static int xmm_power_driver_resume(struct device *dev)
{
pr_debug("%s\n", __func__);
- return 0;
-}
-
-static int baseband_xmm_power_driver_resume(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct baseband_power_platform_data *data
- = (struct baseband_power_platform_data *)
- pdev->dev.platform_data;
- pr_debug("%s\n", __func__);
- baseband_xmm_power_driver_handle_resume(data);
+ /* check if modem is on */
+ if (power_onoff == 0) {
+ pr_debug("%s - flight mode - nop\n", __func__);
+ return 0;
+ }
+ /* PMC is driving hsic bus
+ * tegra_baseband_rail_on();
+ */
+ reenable_autosuspend = true;
return 0;
}
-static int baseband_xmm_power_suspend_noirq(struct device *dev)
+static int xmm_power_suspend_noirq(struct device *dev)
{
unsigned long flags;
@@ -1191,57 +1099,62 @@ static int baseband_xmm_power_suspend_noirq(struct device *dev)
return 0;
}
-static int baseband_xmm_power_resume_noirq(struct device *dev)
+static int xmm_power_resume_noirq(struct device *dev)
{
pr_debug("%s\n", __func__);
return 0;
}
-static const struct dev_pm_ops baseband_xmm_power_dev_pm_ops = {
- .suspend_noirq = baseband_xmm_power_suspend_noirq,
- .resume_noirq = baseband_xmm_power_resume_noirq,
- .suspend = baseband_xmm_power_driver_suspend,
- .resume = baseband_xmm_power_driver_resume,
+static const struct dev_pm_ops xmm_power_dev_pm_ops = {
+ .suspend_noirq = xmm_power_suspend_noirq,
+ .resume_noirq = xmm_power_resume_noirq,
+ .suspend = xmm_power_driver_suspend,
+ .resume = xmm_power_driver_resume,
};
#endif
-static int baseband_xmm_power_driver_shutdown(struct platform_device *device)
+static void xmm_power_driver_shutdown(struct platform_device *device)
{
- struct baseband_power_platform_data *data =
- (struct baseband_power_platform_data *)
- device->dev.platform_data;
+ struct baseband_power_platform_data *pdata = device->dev.platform_data;
pr_debug("%s\n", __func__);
- disable_irq(gpio_to_irq(data->modem.xmm.ipc_ap_wake));
+ disable_irq(gpio_to_irq(pdata->modem.xmm.ipc_ap_wake));
/* bb_on is already down, to make sure set 0 again */
- gpio_set_value(data->modem.xmm.bb_on, 0);
- gpio_set_value(data->modem.xmm.bb_rst, 0);
- return 0;
+ gpio_set_value(pdata->modem.xmm.bb_on, 0);
+ gpio_set_value(pdata->modem.xmm.bb_rst, 0);
+ return;
}
static struct platform_driver baseband_power_driver = {
- .probe = baseband_xmm_power_driver_probe,
- .remove = baseband_xmm_power_driver_remove,
- .shutdown = baseband_xmm_power_driver_shutdown,
+ .probe = xmm_power_driver_probe,
+ .remove = xmm_power_driver_remove,
+ .shutdown = xmm_power_driver_shutdown,
.driver = {
.name = "baseband_xmm_power",
#ifdef CONFIG_PM
- .pm = &baseband_xmm_power_dev_pm_ops,
+ .pm = &xmm_power_dev_pm_ops,
#endif
},
};
-static int __init baseband_xmm_power_init(void)
+static int __init xmm_power_init(void)
{
pr_debug("%s\n", __func__);
+
+ INIT_DELAYED_WORK(&pm_qos_work, pm_qos_worker);
+ pm_qos_add_request(&boost_cpu_freq_req, PM_QOS_CPU_FREQ_MIN,
+ (s32)PM_QOS_CPU_FREQ_MIN_DEFAULT_VALUE);
+
return platform_driver_register(&baseband_power_driver);
}
-static void __exit baseband_xmm_power_exit(void)
+static void __exit xmm_power_exit(void)
{
pr_debug("%s\n", __func__);
platform_driver_unregister(&baseband_power_driver);
+
+ pm_qos_remove_request(&boost_cpu_freq_req);
}
-module_init(baseband_xmm_power_init)
-module_exit(baseband_xmm_power_exit)
+module_init(xmm_power_init)
+module_exit(xmm_power_exit)
diff --git a/arch/arm/mach-tegra/baseband-xmm-power.h b/arch/arm/mach-tegra/baseband-xmm-power.h
index 0768ed191b05..69140891319d 100644
--- a/arch/arm/mach-tegra/baseband-xmm-power.h
+++ b/arch/arm/mach-tegra/baseband-xmm-power.h
@@ -71,24 +71,22 @@ enum baseband_xmm_power_work_state_t {
BBXMM_WORK_INIT_FLASH_STEP1,
/* initialize flash (with power management support) modem */
BBXMM_WORK_INIT_FLASH_PM_STEP1,
- BBXMM_WORK_INIT_FLASH_PM_VER_LT_1130_STEP1,
- BBXMM_WORK_INIT_FLASH_PM_VER_GE_1130_STEP1,
/* initialize flashless (with power management support) modem */
BBXMM_WORK_INIT_FLASHLESS_PM_STEP1,
- BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_WAIT_IRQ,
- BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_STEP1,
- BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_STEP2,
- BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP1,
- BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP2,
- BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP3,
- BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP4,
+ BBXMM_WORK_INIT_FLASHLESS_PM_STEP2,
+ BBXMM_WORK_INIT_FLASHLESS_PM_STEP3,
+ BBXMM_WORK_INIT_FLASHLESS_PM_STEP4,
};
-struct baseband_xmm_power_work_t {
- /* work structure must be first structure member */
- struct work_struct work;
+struct xmm_power_data {
/* xmm modem state */
enum baseband_xmm_power_work_state_t state;
+ struct baseband_power_platform_data *pdata;
+ struct work_struct work;
+ struct platform_device *hsic_device;
+ wait_queue_head_t bb_wait;
+ /* host wakeup gpio state*/
+ unsigned int hostwake;
};
enum baseband_xmm_powerstate_t {
@@ -104,8 +102,9 @@ enum baseband_xmm_powerstate_t {
BBXMM_PS_LAST = -1,
};
-irqreturn_t baseband_xmm_power_ipc_ap_wake_irq(int irq, void *dev_id);
+irqreturn_t xmm_power_ipc_ap_wake_irq(int irq, void *dev_id);
void baseband_xmm_set_power_status(unsigned int status);
+extern struct xmm_power_data xmm_power_drv_data;
#endif /* BASREBAND_XMM_POWER_H */
diff --git a/arch/arm/mach-tegra/baseband-xmm-power2.c b/arch/arm/mach-tegra/baseband-xmm-power2.c
index 4295b3958202..3c6285c0a070 100644
--- a/arch/arm/mach-tegra/baseband-xmm-power2.c
+++ b/arch/arm/mach-tegra/baseband-xmm-power2.c
@@ -32,8 +32,6 @@
#include "board.h"
#include "devices.h"
-MODULE_LICENSE("GPL");
-
static unsigned long XYZ = 1000 * 1000000 + 800 * 1000 + 500;
module_param(modem_ver, ulong, 0644);
@@ -49,9 +47,8 @@ module_param(XYZ, ulong, 0644);
MODULE_PARM_DESC(XYZ,
"baseband xmm power2 - timing parameters X/Y/Z delay in ms");
-static struct baseband_power_platform_data *baseband_power2_driver_data;
static struct workqueue_struct *workqueue;
-static struct baseband_xmm_power_work_t *baseband_xmm_power2_work;
+static bool free_ipc_ap_wake_irq;
static enum {
IPC_AP_WAKE_UNINIT,
@@ -62,105 +59,37 @@ static enum {
IPC_AP_WAKE_H,
} ipc_ap_wake_state;
-static irqreturn_t baseband_xmm_power2_ver_lt_1130_ipc_ap_wake_irq2
- (int irq, void *dev_id)
-{
- int value;
-
- pr_debug("%s\n", __func__);
-
- /* check for platform data */
- if (!baseband_power2_driver_data)
- return IRQ_HANDLED;
- value = gpio_get_value(baseband_power2_driver_data->
- modem.xmm.ipc_ap_wake);
-
- /* IPC_AP_WAKE state machine */
- if (ipc_ap_wake_state < IPC_AP_WAKE_IRQ_READY) {
- pr_err("%s - spurious irq\n", __func__);
- } else if (ipc_ap_wake_state == IPC_AP_WAKE_IRQ_READY) {
- if (!value) {
- pr_debug("%s - IPC_AP_WAKE_INIT1"
- " - got falling edge\n",
- __func__);
- /* go to IPC_AP_WAKE_INIT1 state */
- ipc_ap_wake_state = IPC_AP_WAKE_INIT1;
- /* queue work */
- baseband_xmm_power2_work->state =
- BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_STEP1;
- queue_work(workqueue, (struct work_struct *)
- baseband_xmm_power2_work);
- } else {
- pr_debug("%s - IPC_AP_WAKE_INIT1"
- " - wait for falling edge\n",
- __func__);
- }
- } else if (ipc_ap_wake_state == IPC_AP_WAKE_INIT1) {
- if (!value) {
- pr_debug("%s - IPC_AP_WAKE_INIT2"
- " - wait for rising edge\n",
- __func__);
- } else {
- pr_debug("%s - IPC_AP_WAKE_INIT2"
- " - got rising edge\n",
- __func__);
- /* go to IPC_AP_WAKE_INIT2 state */
- ipc_ap_wake_state = IPC_AP_WAKE_INIT2;
- /* queue work */
- baseband_xmm_power2_work->state =
- BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_STEP2;
- queue_work(workqueue, (struct work_struct *)
- baseband_xmm_power2_work);
- }
- } else {
- if (!value) {
- pr_debug("%s - falling\n", __func__);
- ipc_ap_wake_state = IPC_AP_WAKE_L;
- } else {
- pr_debug("%s - rising\n", __func__);
- ipc_ap_wake_state = IPC_AP_WAKE_H;
- }
- return baseband_xmm_power_ipc_ap_wake_irq(irq, dev_id);
- }
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t baseband_xmm_power2_ver_ge_1130_ipc_ap_wake_irq2
- (int irq, void *dev_id)
+static irqreturn_t xmm_power2_ipc_ap_wake_irq(int irq, void *dev_id)
{
int value;
+ struct xmm_power_data *data = dev_id;
+ struct baseband_power_platform_data *pdata = data->pdata;
pr_debug("%s\n", __func__);
/* check for platform data */
- if (!baseband_power2_driver_data)
+ if (!pdata)
return IRQ_HANDLED;
- value = gpio_get_value(baseband_power2_driver_data->
- modem.xmm.ipc_ap_wake);
+ value = gpio_get_value(pdata->modem.xmm.ipc_ap_wake);
/* IPC_AP_WAKE state machine */
- if (ipc_ap_wake_state < IPC_AP_WAKE_IRQ_READY) {
+ if (unlikely(ipc_ap_wake_state < IPC_AP_WAKE_IRQ_READY))
pr_err("%s - spurious irq\n", __func__);
- } else if (ipc_ap_wake_state == IPC_AP_WAKE_IRQ_READY) {
+ else if (ipc_ap_wake_state == IPC_AP_WAKE_IRQ_READY) {
if (!value) {
- pr_debug("%s - IPC_AP_WAKE_INIT1"
- " - got falling edge\n",
+ pr_debug("%s: IPC_AP_WAKE_INIT1 got falling edge\n",
__func__);
/* go to IPC_AP_WAKE_INIT2 state */
ipc_ap_wake_state = IPC_AP_WAKE_INIT2;
/* queue work */
- baseband_xmm_power2_work->state =
- BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP2;
- queue_work(workqueue, (struct work_struct *)
- baseband_xmm_power2_work);
- } else {
- pr_debug("%s - IPC_AP_WAKE_INIT1"
- " - wait for falling edge\n",
- __func__);
- }
+ data->state =
+ BBXMM_WORK_INIT_FLASHLESS_PM_STEP2;
+ queue_work(workqueue, &data->work);
+ } else
+ pr_debug("%s: IPC_AP_WAKE_INIT1"
+ " wait for falling edge\n", __func__);
} else {
if (!value) {
pr_debug("%s - falling\n", __func__);
@@ -169,260 +98,154 @@ static irqreturn_t baseband_xmm_power2_ver_ge_1130_ipc_ap_wake_irq2
pr_debug("%s - rising\n", __func__);
ipc_ap_wake_state = IPC_AP_WAKE_H;
}
- return baseband_xmm_power_ipc_ap_wake_irq(irq, dev_id);
+ return xmm_power_ipc_ap_wake_irq(irq, dev_id);
}
return IRQ_HANDLED;
}
-static void baseband_xmm_power2_flashless_pm_ver_lt_1130_step1
- (struct work_struct *work)
-{
- int value;
-
- pr_debug("%s {\n", __func__);
-
- /* check for platform data */
- if (!baseband_power2_driver_data)
- return;
-
- /* check if IPC_HSIC_ACTIVE high */
- value = gpio_get_value(baseband_power2_driver_data->
- modem.xmm.ipc_hsic_active);
- if (value != 1) {
- pr_err("%s - expected IPC_HSIC_ACTIVE high!\n", __func__);
- return;
- }
-
- /* wait 30 ms */
- mdelay(30);
-
- /* set IPC_HSIC_ACTIVE low */
- gpio_set_value(baseband_power2_driver_data->
- modem.xmm.ipc_hsic_active, 0);
-
- pr_debug("%s }\n", __func__);
-}
-
-static void baseband_xmm_power2_flashless_pm_ver_lt_1130_step2
- (struct work_struct *work)
-{
- int value;
-
- pr_debug("%s {\n", __func__);
-
- /* check for platform data */
- if (!baseband_power2_driver_data)
- return;
-
- /* check if IPC_HSIC_ACTIVE low */
- value = gpio_get_value(baseband_power2_driver_data->
- modem.xmm.ipc_hsic_active);
- if (value != 0) {
- pr_err("%s - expected IPC_HSIC_ACTIVE low!\n", __func__);
- return;
- }
-
- /* wait 1 ms */
- mdelay(1);
-
- /* unregister usb host controller */
- if (baseband_power2_driver_data->hsic_unregister)
- baseband_power2_driver_data->hsic_unregister(
- baseband_power2_driver_data->modem.xmm.hsic_device);
- else
- pr_err("%s: hsic_unregister is missing\n", __func__);
-
- /* set IPC_HSIC_ACTIVE high */
- gpio_set_value(baseband_power2_driver_data->
- modem.xmm.ipc_hsic_active, 1);
-
- /* wait 20 ms */
- mdelay(20);
-
- /* set IPC_HSIC_ACTIVE low */
- gpio_set_value(baseband_power2_driver_data->
- modem.xmm.ipc_hsic_active, 0);
-
- /* wait 20 ms */
- mdelay(20);
-
- /* set IPC_HSIC_ACTIVE high */
- gpio_set_value(baseband_power2_driver_data->
- modem.xmm.ipc_hsic_active, 1);
-
- pr_debug("%s }\n", __func__);
-}
-
-static void baseband_xmm_power2_flashless_pm_ver_ge_1130_step1
- (struct work_struct *work)
+static void xmm_power2_step1(struct work_struct *work)
{
+ struct xmm_power_data *data =
+ container_of(work, struct xmm_power_data, work);
+ struct baseband_power_platform_data *pdata = data->pdata;
int X = XYZ / 1000000;
- int Y = XYZ / 1000 - X * 1000;
- int Z = XYZ % 1000;
pr_info("%s {\n", __func__);
- pr_info("XYZ=%ld X=%d Y=%d Z=%d\n", XYZ, X, Y, Z);
-
/* check for platform data */
- if (!baseband_power2_driver_data)
+ if (!pdata)
return;
/* unregister usb host controller */
- if (baseband_power2_driver_data->hsic_unregister)
- baseband_power2_driver_data->hsic_unregister(
- baseband_power2_driver_data->modem.xmm.hsic_device);
+ if (pdata->hsic_unregister)
+ pdata->hsic_unregister(data->hsic_device);
else
pr_err("%s: hsic_unregister is missing\n", __func__);
/* wait X ms */
- mdelay(X);
+ msleep(X);
/* set IPC_HSIC_ACTIVE low */
- gpio_set_value(baseband_power2_driver_data->
- modem.xmm.ipc_hsic_active, 0);
+ gpio_set_value(pdata->modem.xmm.ipc_hsic_active, 0);
pr_info("%s }\n", __func__);
}
-static void baseband_xmm_power2_flashless_pm_ver_ge_1130_step2
- (struct work_struct *work)
+static void xmm_power2_step2(struct work_struct *work)
{
+ struct xmm_power_data *data =
+ container_of(work, struct xmm_power_data, work);
+ struct baseband_power_platform_data *pdata = data->pdata;
int X = XYZ / 1000000;
int Y = XYZ / 1000 - X * 1000;
int Z = XYZ % 1000;
pr_info("%s {\n", __func__);
- pr_info("XYZ=%ld X=%d Y=%d Z=%d\n", XYZ, X, Y, Z);
-
/* check for platform data */
- if (!baseband_power2_driver_data)
+ if (!data || !pdata)
return;
/* wait Y ms */
- mdelay(Y);
+ msleep(Y);
/* register usb host controller */
- if (baseband_power2_driver_data->hsic_register)
- baseband_power2_driver_data->modem.xmm.hsic_device =
- baseband_power2_driver_data->hsic_register();
+ if (pdata->hsic_register)
+ data->hsic_device = pdata->hsic_register();
else
pr_err("%s: hsic_register is missing\n", __func__);
/* wait Z ms */
- mdelay(Z);
+ msleep(Z);
/* set IPC_HSIC_ACTIVE high */
- gpio_set_value(baseband_power2_driver_data->
- modem.xmm.ipc_hsic_active, 1);
+ gpio_set_value(pdata->modem.xmm.ipc_hsic_active, 1);
/* queue work function to check if enumeration succeeded */
- baseband_xmm_power2_work->state =
- BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP3;
- queue_work(workqueue, (struct work_struct *)
- baseband_xmm_power2_work);
+ data->state = BBXMM_WORK_INIT_FLASHLESS_PM_STEP3;
+ queue_work(workqueue, &data->work);
pr_info("%s }\n", __func__);
}
-static void baseband_xmm_power2_flashless_pm_ver_ge_1130_step3
- (struct work_struct *work)
+static void xmm_power2_step3(struct work_struct *work)
{
- int X = XYZ / 1000000;
- int Y = XYZ / 1000 - X * 1000;
- int Z = XYZ % 1000;
+ struct xmm_power_data *data =
+ container_of(work, struct xmm_power_data, work);
+ struct baseband_power_platform_data *pdata = data->pdata;
int enum_success = 0;
+ mm_segment_t oldfs;
+ struct file *filp;
pr_info("%s {\n", __func__);
- pr_info("XYZ=%ld X=%d Y=%d Z=%d\n", XYZ, X, Y, Z);
-
/* check for platform data */
- if (!baseband_power2_driver_data)
+ if (!data || !pdata)
return;
- /* wait 500 ms */
- mdelay(500);
+ /* wait 1 sec */
+ msleep(1000);
/* check if enumeration succeeded */
- {
- mm_segment_t oldfs;
- struct file *filp;
- oldfs = get_fs();
- set_fs(KERNEL_DS);
- filp = filp_open("/dev/ttyACM0",
- O_RDONLY, 0);
- if (IS_ERR(filp) || (filp == NULL)) {
- pr_err("/dev/ttyACM0 %ld\n",
- PTR_ERR(filp));
- } else {
- filp_close(filp, NULL);
- enum_success = 1;
- }
- set_fs(oldfs);
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+ filp = filp_open("/dev/ttyACM0", O_RDONLY, 0);
+ if (IS_ERR(filp) || (filp == NULL))
+ pr_err("failed to open /dev/ttyACM0 %ld\n", PTR_ERR(filp));
+ else {
+ filp_close(filp, NULL);
+ enum_success = 1;
}
+ set_fs(oldfs);
/* if enumeration failed, attempt recovery pulse */
if (!enum_success) {
pr_info("attempting recovery pulse...\n");
/* wait 20 ms */
- mdelay(20);
+ msleep(20);
/* set IPC_HSIC_ACTIVE low */
- gpio_set_value(baseband_power2_driver_data->
- modem.xmm.ipc_hsic_active, 0);
+ gpio_set_value(pdata->modem.xmm.ipc_hsic_active, 0);
/* wait 20 ms */
- mdelay(20);
+ msleep(20);
/* set IPC_HSIC_ACTIVE high */
- gpio_set_value(baseband_power2_driver_data->
- modem.xmm.ipc_hsic_active, 1);
+ gpio_set_value(pdata->modem.xmm.ipc_hsic_active, 1);
/* check if recovery pulse worked */
- baseband_xmm_power2_work->state =
- BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP4;
- queue_work(workqueue, (struct work_struct *)
- baseband_xmm_power2_work);
+ data->state = BBXMM_WORK_INIT_FLASHLESS_PM_STEP4;
+ queue_work(workqueue, &data->work);
}
pr_info("%s }\n", __func__);
}
-static void baseband_xmm_power2_flashless_pm_ver_ge_1130_step4
- (struct work_struct *work)
+static void xmm_power2_step4(struct work_struct *work)
{
- int X = XYZ / 1000000;
- int Y = XYZ / 1000 - X * 1000;
- int Z = XYZ % 1000;
+ struct xmm_power_data *data =
+ container_of(work, struct xmm_power_data, work);
+ mm_segment_t oldfs;
+ struct file *filp;
int enum_success = 0;
pr_info("%s {\n", __func__);
- pr_info("XYZ=%ld X=%d Y=%d Z=%d\n", XYZ, X, Y, Z);
-
/* check for platform data */
- if (!baseband_power2_driver_data)
+ if (!data)
return;
/* wait 500 ms */
- mdelay(500);
+ msleep(500);
/* check if enumeration succeeded */
- {
- mm_segment_t oldfs;
- struct file *filp;
- oldfs = get_fs();
- set_fs(KERNEL_DS);
- filp = filp_open("/dev/ttyACM0",
- O_RDONLY, 0);
- if (IS_ERR(filp) || (filp == NULL)) {
- pr_err("open /dev/ttyACM0 failed %ld\n",
- PTR_ERR(filp));
- } else {
- filp_close(filp, NULL);
- enum_success = 1;
- }
- set_fs(oldfs);
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+ filp = filp_open("/dev/ttyACM0", O_RDONLY, 0);
+ if (IS_ERR(filp) || (filp == NULL))
+ pr_err("failed to open /dev/ttyACM0 %ld\n", PTR_ERR(filp));
+ else {
+ filp_close(filp, NULL);
+ enum_success = 1;
}
+ set_fs(oldfs);
/* if recovery pulse did not fix enumeration, retry from beginning */
if (!enum_success) {
@@ -438,34 +261,31 @@ static void baseband_xmm_power2_flashless_pm_ver_ge_1130_step4
retry);
--retry;
ipc_ap_wake_state = IPC_AP_WAKE_IRQ_READY;
- baseband_xmm_power2_work->state =
- BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP1;
- queue_work(workqueue, (struct work_struct *)
- baseband_xmm_power2_work);
+ data->state = BBXMM_WORK_INIT_FLASHLESS_PM_STEP1;
+ queue_work(workqueue, &data->work);
}
}
pr_info("%s }\n", __func__);
}
-static int free_ipc_ap_wake_irq;
-
-static void baseband_xmm_power2_work_func(struct work_struct *work)
+static void xmm_power2_work_func(struct work_struct *work)
{
- struct baseband_xmm_power_work_t *bbxmm_work
- = (struct baseband_xmm_power_work_t *) work;
+ struct xmm_power_data *data =
+ container_of(work, struct xmm_power_data, work);
+ struct baseband_power_platform_data *pdata = data->pdata;
int err;
- pr_debug("%s bbxmm_work->state=%d\n", __func__, bbxmm_work->state);
+ pr_debug("%s pdata->state=%d\n", __func__, data->state);
- switch (bbxmm_work->state) {
+ switch (data->state) {
case BBXMM_WORK_UNINIT:
pr_debug("BBXMM_WORK_UNINIT\n");
/* free baseband irq(s) */
if (free_ipc_ap_wake_irq) {
- free_irq(gpio_to_irq(baseband_power2_driver_data
- ->modem.xmm.ipc_ap_wake), NULL);
- free_ipc_ap_wake_irq = 0;
+ free_irq(gpio_to_irq(pdata->modem.xmm.ipc_ap_wake),
+ data);
+ free_ipc_ap_wake_irq = false;
}
break;
case BBXMM_WORK_INIT:
@@ -473,24 +293,20 @@ static void baseband_xmm_power2_work_func(struct work_struct *work)
/* request baseband irq(s) */
ipc_ap_wake_state = IPC_AP_WAKE_UNINIT;
err = request_threaded_irq(
- gpio_to_irq(baseband_power2_driver_data->
- modem.xmm.ipc_ap_wake),
- NULL,
- (modem_ver < XMM_MODEM_VER_1130)
- ? baseband_xmm_power2_ver_lt_1130_ipc_ap_wake_irq2
- : baseband_xmm_power2_ver_ge_1130_ipc_ap_wake_irq2,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "BBXMM_POWER2_IPC_AP_WAKE_IRQ",
- NULL);
+ gpio_to_irq(pdata->modem.xmm.ipc_ap_wake),
+ NULL, xmm_power2_ipc_ap_wake_irq,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ "xmm_power2_ipc_ap_wake_irq", data);
if (err < 0) {
pr_err("%s - request irq IPC_AP_WAKE_IRQ failed\n",
__func__);
return;
}
- free_ipc_ap_wake_irq = 1;
+ free_ipc_ap_wake_irq = true;
ipc_ap_wake_state = IPC_AP_WAKE_IRQ_READY;
+
/* go to next state */
- bbxmm_work->state = (modem_flash && !modem_pm)
+ data->state = (modem_flash && !modem_pm)
? BBXMM_WORK_INIT_FLASH_STEP1
: (modem_flash && modem_pm)
? BBXMM_WORK_INIT_FLASH_PM_STEP1
@@ -501,130 +317,93 @@ static void baseband_xmm_power2_work_func(struct work_struct *work)
break;
case BBXMM_WORK_INIT_FLASH_STEP1:
pr_debug("BBXMM_WORK_INIT_FLASH_STEP1\n");
+ pr_info("%s: flashed modem is not supported here\n", __func__);
break;
case BBXMM_WORK_INIT_FLASH_PM_STEP1:
pr_debug("BBXMM_WORK_INIT_FLASH_PM_STEP1\n");
- /* go to next state */
- bbxmm_work->state = (modem_ver < XMM_MODEM_VER_1130)
- ? BBXMM_WORK_INIT_FLASH_PM_VER_LT_1130_STEP1
- : BBXMM_WORK_INIT_FLASH_PM_VER_GE_1130_STEP1;
- queue_work(workqueue, work);
- break;
- case BBXMM_WORK_INIT_FLASH_PM_VER_LT_1130_STEP1:
- pr_debug("BBXMM_WORK_INIT_FLASH_PM_VER_LT_1130_STEP1\n");
- break;
- case BBXMM_WORK_INIT_FLASH_PM_VER_GE_1130_STEP1:
- pr_debug("BBXMM_WORK_INIT_FLASH_PM_VER_GE_1130_STEP1\n");
+ pr_info("%s: flashed modem is not supported here\n", __func__);
break;
case BBXMM_WORK_INIT_FLASHLESS_PM_STEP1:
+ /* start flashless modem enum process */
pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_STEP1\n");
- /* go to next state */
- bbxmm_work->state = (modem_ver < XMM_MODEM_VER_1130)
- ? BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_WAIT_IRQ
- : BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP1;
- queue_work(workqueue, work);
- break;
- case BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_WAIT_IRQ:
- pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_WAIT_IRQ"
- " - waiting for IPC_AP_WAKE_IRQ to trigger step1\n");
- break;
- case BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_STEP1:
- pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_STEP1\n");
- baseband_xmm_power2_flashless_pm_ver_lt_1130_step1(work);
+ xmm_power2_step1(work);
break;
- case BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_STEP2:
- pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_VER_LT_1130_STEP2\n");
- baseband_xmm_power2_flashless_pm_ver_lt_1130_step2(work);
+ case BBXMM_WORK_INIT_FLASHLESS_PM_STEP2:
+ pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_STEP2\n");
+ xmm_power2_step2(work);
break;
- case BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP1:
- pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP1\n");
- baseband_xmm_power2_flashless_pm_ver_ge_1130_step1(work);
+ case BBXMM_WORK_INIT_FLASHLESS_PM_STEP3:
+ pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_STEP3\n");
+ xmm_power2_step3(work);
break;
- case BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP2:
- pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP2\n");
- baseband_xmm_power2_flashless_pm_ver_ge_1130_step2(work);
+ case BBXMM_WORK_INIT_FLASHLESS_PM_STEP4:
+ pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_STEP4\n");
+ xmm_power2_step4(work);
break;
- case BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP3:
- pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP3\n");
- baseband_xmm_power2_flashless_pm_ver_ge_1130_step3(work);
- break;
- case BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP4:
- pr_debug("BBXMM_WORK_INIT_FLASHLESS_PM_VER_GE_1130_STEP4\n");
- baseband_xmm_power2_flashless_pm_ver_ge_1130_step4(work);
+ default:
break;
}
-
}
-static int baseband_xmm_power2_driver_probe(struct platform_device *device)
+static int xmm_power2_probe(struct platform_device *device)
{
- struct baseband_power_platform_data *data
- = (struct baseband_power_platform_data *)
- device->dev.platform_data;
-
pr_debug("%s\n", __func__);
+ if (!device->dev.platform_data) {
+ pr_err("%s: no platform data found\n", __func__);
+ return -ENOMEM;
+ }
- /* save platform data */
- baseband_power2_driver_data = data;
+ xmm_power_drv_data.pdata = device->dev.platform_data;
- /* init work queue */
+ /* create workqueue */
pr_debug("%s: init work queue\n", __func__);
- workqueue = create_singlethread_workqueue
- ("baseband_xmm_power2_workqueue");
- if (!workqueue) {
- pr_err("cannot create workqueue\n");
- return -1;
- }
- baseband_xmm_power2_work = (struct baseband_xmm_power_work_t *)
- kmalloc(sizeof(struct baseband_xmm_power_work_t), GFP_KERNEL);
- if (!baseband_xmm_power2_work) {
- pr_err("cannot allocate baseband_xmm_power2_work\n");
- return -1;
+ workqueue = create_singlethread_workqueue("xmm_power2_wq");
+ if (unlikely(!workqueue)) {
+ pr_err("%s: cannot create workqueue\n", __func__);
+ return -ENOMEM;
}
+
+ /* init work */
pr_debug("%s: BBXMM_WORK_INIT\n", __func__);
- INIT_WORK((struct work_struct *) baseband_xmm_power2_work,
- baseband_xmm_power2_work_func);
- baseband_xmm_power2_work->state = BBXMM_WORK_INIT;
- queue_work(workqueue,
- (struct work_struct *) baseband_xmm_power2_work);
+ INIT_WORK(&xmm_power_drv_data.work, xmm_power2_work_func);
+ xmm_power_drv_data.state = BBXMM_WORK_INIT;
+ queue_work(workqueue, &xmm_power_drv_data.work);
+
return 0;
}
-static int baseband_xmm_power2_driver_remove(struct platform_device *device)
+static int xmm_power2_remove(struct platform_device *device)
{
- struct baseband_power_platform_data *data
- = (struct baseband_power_platform_data *)
+ struct baseband_power_platform_data *pdata =
device->dev.platform_data;
+ struct xmm_power_data *data = &xmm_power_drv_data;
pr_debug("%s\n", __func__);
/* check for platform data */
if (!data)
- return 0;
-
- /* free irq */
- if (free_ipc_ap_wake_irq) {
- free_irq(gpio_to_irq(data->modem.xmm.ipc_ap_wake), NULL);
- free_ipc_ap_wake_irq = 0;
- }
+ return -ENODEV;
- /* free work structure */
+ /* free work queue */
if (workqueue) {
- cancel_work_sync(baseband_xmm_power2_work);
+ cancel_work_sync(&data->work);
destroy_workqueue(workqueue);
}
- kfree(baseband_xmm_power2_work);
- baseband_xmm_power2_work = (struct baseband_xmm_power_work_t *) 0;
+
+ /* free irq */
+ if (free_ipc_ap_wake_irq) {
+ free_irq(gpio_to_irq(pdata->modem.xmm.ipc_ap_wake), data);
+ free_ipc_ap_wake_irq = false;
+ }
return 0;
}
#ifdef CONFIG_PM
-static int baseband_xmm_power2_driver_suspend(struct platform_device *device,
+static int xmm_power2_suspend(struct platform_device *device,
pm_message_t state)
{
- struct baseband_power_platform_data *data
- = (struct baseband_power_platform_data *)
+ struct baseband_power_platform_data *data =
device->dev.platform_data;
pr_debug("%s - nop\n", __func__);
@@ -636,10 +415,9 @@ static int baseband_xmm_power2_driver_suspend(struct platform_device *device,
return 0;
}
-static int baseband_xmm_power2_driver_resume(struct platform_device *device)
+static int xmm_power2_resume(struct platform_device *device)
{
- struct baseband_power_platform_data *data
- = (struct baseband_power_platform_data *)
+ struct baseband_power_platform_data *data =
device->dev.platform_data;
pr_debug("%s - nop\n", __func__);
@@ -653,29 +431,32 @@ static int baseband_xmm_power2_driver_resume(struct platform_device *device)
#endif
static struct platform_driver baseband_power2_driver = {
- .probe = baseband_xmm_power2_driver_probe,
- .remove = baseband_xmm_power2_driver_remove,
+ .probe = xmm_power2_probe,
+ .remove = xmm_power2_remove,
#ifdef CONFIG_PM
- .suspend = baseband_xmm_power2_driver_suspend,
- .resume = baseband_xmm_power2_driver_resume,
+ .suspend = xmm_power2_suspend,
+ .resume = xmm_power2_resume,
#endif
.driver = {
.name = "baseband_xmm_power2",
},
};
-static int __init baseband_xmm_power2_init(void)
+static int __init xmm_power2_init(void)
{
pr_debug("%s\n", __func__);
return platform_driver_register(&baseband_power2_driver);
}
-static void __exit baseband_xmm_power2_exit(void)
+static void __exit xmm_power2_exit(void)
{
pr_debug("%s\n", __func__);
+
platform_driver_unregister(&baseband_power2_driver);
}
-module_init(baseband_xmm_power2_init)
-module_exit(baseband_xmm_power2_exit)
+module_init(xmm_power2_init)
+module_exit(xmm_power2_exit)
+
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-tegra/board-aruba-panel.c b/arch/arm/mach-tegra/board-aruba-panel.c
index b014326fc91b..01ade01a0eb6 100644
--- a/arch/arm/mach-tegra/board-aruba-panel.c
+++ b/arch/arm/mach-tegra/board-aruba-panel.c
@@ -26,7 +26,7 @@
#include <linux/platform_device.h>
#include <linux/pwm_backlight.h>
#include <linux/nvhost.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include <mach/irqs.h>
#include <mach/iomap.h>
#include <mach/dc.h>
@@ -35,6 +35,7 @@
#include "board.h"
#include "devices.h"
#include "gpio-names.h"
+#include "tegra2_host1x_devices.h"
#define aruba_lvds_shutdown TEGRA_GPIO_PB2
#define aruba_bl_enb TEGRA_GPIO_PW1
@@ -228,7 +229,7 @@ int __init aruba_panel_init(void)
#endif
#ifdef CONFIG_TEGRA_GRHOST
- err = nvhost_device_register(&tegra_grhost_device);
+ err = tegra2_register_host1x_devices();
if (err)
return err;
#endif
diff --git a/arch/arm/mach-tegra/board-aruba-power.c b/arch/arm/mach-tegra/board-aruba-power.c
index 4391f6f19b51..b72b82fc144a 100644
--- a/arch/arm/mach-tegra/board-aruba-power.c
+++ b/arch/arm/mach-tegra/board-aruba-power.c
@@ -26,7 +26,6 @@
#include "pm.h"
#include "board.h"
-#include "wakeups-t3.h"
static int ac_online(void)
{
diff --git a/arch/arm/mach-tegra/board-aruba.c b/arch/arm/mach-tegra/board-aruba.c
index 152f34720489..2fc524ccef93 100644
--- a/arch/arm/mach-tegra/board-aruba.c
+++ b/arch/arm/mach-tegra/board-aruba.c
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/board-aruba.c
*
- * 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
@@ -47,6 +47,7 @@
#include <asm/mach/arch.h>
#include <mach/usb_phy.h>
#include <mach/nand.h>
+#include <mach/tegra_fiq_debugger.h>
#include "board.h"
#include "clock.h"
#include "board-aruba.h"
@@ -446,7 +447,9 @@ static struct platform_device *aruba_devices[] __initdata = {
&tegra_smmu_device,
#endif
&aruba_keys_device,
- &tegra_wdt_device,
+ &tegra_wdt0_device,
+ &tegra_wdt1_device,
+ &tegra_wdt2_device,
#if defined(CONFIG_SND_HDA_TEGRA)
&tegra_hda_device,
#endif
@@ -522,6 +525,7 @@ static void __init tegra_aruba_init(void)
aruba_bt_rfkill();
aruba_sata_init();
tegra_release_bootloader_fb();
+ tegra_serial_debug_init(TEGRA_UARTD_BASE, INT_WDT_CPU, NULL, -1, -1);
}
static void __init tegra_aruba_reserve(void)
diff --git a/arch/arm/mach-tegra/board-cardhu-kbc.c b/arch/arm/mach-tegra/board-cardhu-kbc.c
index 3bf0a3b864fc..c3971403148f 100644
--- a/arch/arm/mach-tegra/board-cardhu-kbc.c
+++ b/arch/arm/mach-tegra/board-cardhu-kbc.c
@@ -174,7 +174,8 @@ static struct gpio_keys_button cardhu_keys_e1291_a04[] = {
[3] = GPIO_KEY(KEY_SEARCH, PQ3, 0),
[4] = GPIO_KEY(KEY_BACK, PQ0, 0),
[5] = GPIO_KEY(KEY_MENU, PQ1, 0),
- [6] = GPIO_IKEY(KEY_POWER, TPS6591X_IRQ_BASE + TPS6591X_INT_PWRON, 1, 100),
+ [6] = GPIO_KEY(KEY_RESERVED, PV0, 1),
+ [7] = GPIO_IKEY(KEY_POWER, TPS6591X_IRQ_BASE + TPS6591X_INT_PWRON, 1, 100),
};
static struct gpio_keys_platform_data cardhu_keys_e1291_pdata = {
@@ -195,12 +196,12 @@ static struct gpio_keys_button cardhu_int_keys[] = {
};
static struct gpio_keys_button cardhu_pm298_int_keys[] = {
- [0] = GPIO_IKEY(KEY_POWER, MAX77663_IRQ_BASE + MAX77663_IRQ_ONOFF_EN0_FALLING, 1, 100),
- [1] = GPIO_IKEY(KEY_POWER, MAX77663_IRQ_BASE + MAX77663_IRQ_ONOFF_EN0_1SEC, 1, 3000),
+ [0] = GPIO_IKEY(KEY_POWER, MAX77663_IRQ_BASE + MAX77663_IRQ_ONOFF_EN0_FALLING, 0, 100),
+ [1] = GPIO_IKEY(KEY_POWER, MAX77663_IRQ_BASE + MAX77663_IRQ_ONOFF_EN0_1SEC, 0, 3000),
};
static struct gpio_keys_button cardhu_pm299_int_keys[] = {
- [0] = GPIO_IKEY(KEY_POWER, RICOH583_IRQ_BASE + RICOH583_IRQ_ONKEY, 1, 100),
+ [0] = GPIO_KEY(KEY_POWER, PV0, 1),
};
static struct gpio_keys_platform_data cardhu_int_keys_pdata = {
@@ -230,6 +231,7 @@ int __init cardhu_keys_init(void)
(board_info.board_id == BOARD_E1257) ||
(board_info.board_id == BOARD_PM305) ||
(board_info.board_id == BOARD_PM311) ||
+ (board_info.board_id == BOARD_PM267) ||
(board_info.board_id == BOARD_PM269)))
return 0;
@@ -250,8 +252,6 @@ int __init cardhu_keys_init(void)
if (get_tegra_image_type() == rck_image)
cardhu_keys_e1291_pdata.buttons[i].code
= KEY_ENTER;
- } else {
- tegra_gpio_enable(gpio_nr);
}
}
@@ -263,8 +263,6 @@ int __init cardhu_keys_init(void)
if (gpio_nr < 0) {
if (get_tegra_image_type() == rck_image)
cardhu_keys_e1198[i].code = KEY_ENTER;
- } else {
- tegra_gpio_enable(gpio_nr);
}
}
@@ -290,6 +288,7 @@ int __init cardhu_keys_init(void)
(board_info.board_id == BOARD_E1186) ||
(board_info.board_id == BOARD_PM305) ||
(board_info.board_id == BOARD_PM311) ||
+ (board_info.board_id == BOARD_PM267) ||
(board_info.board_id == BOARD_PM269)) {
if (get_tegra_image_type() == rck_image)
cardhu_int_keys[0].code = KEY_ENTER;
diff --git a/arch/arm/mach-tegra/board-cardhu-memory.c b/arch/arm/mach-tegra/board-cardhu-memory.c
index 0cd9e0066668..1ed99a9fa1fa 100644
--- a/arch/arm/mach-tegra/board-cardhu-memory.c
+++ b/arch/arm/mach-tegra/board-cardhu-memory.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 NVIDIA, 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 version 2 as
@@ -2539,6 +2539,246 @@ static const struct tegra_emc_table cardhu_emc_tables_h5tc2g_a2_2GB1R[] = {
},
{
0x32, /* Rev 3.2 */
+ 400000, /* SDRAM frequency */
+ {
+ 0x00000012, /* EMC_RC */
+ 0x00000066, /* EMC_RFC */
+ 0x0000000c, /* EMC_RAS */
+ 0x00000004, /* EMC_RP */
+ 0x00000003, /* EMC_R2W */
+ 0x00000008, /* EMC_W2R */
+ 0x00000002, /* EMC_R2P */
+ 0x0000000a, /* EMC_W2P */
+ 0x00000004, /* EMC_RD_RCD */
+ 0x00000004, /* EMC_WR_RCD */
+ 0x00000002, /* EMC_RRD */
+ 0x00000001, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000004, /* EMC_WDV */
+ 0x00000006, /* EMC_QUSE */
+ 0x00000004, /* EMC_QRST */
+ 0x0000000a, /* EMC_QSAFE */
+ 0x0000000d, /* EMC_RDV */
+ 0x00000bf0, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x000002fc, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x00000001, /* EMC_PDEX2WR */
+ 0x00000008, /* EMC_PDEX2RD */
+ 0x00000001, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x00000008, /* EMC_AR2PDEN */
+ 0x0000000f, /* EMC_RW2PDEN */
+ 0x0000006c, /* EMC_TXSR */
+ 0x00000200, /* EMC_TXSRDLL */
+ 0x00000004, /* EMC_TCKE */
+ 0x0000000c, /* EMC_TFAW */
+ 0x00000000, /* EMC_TRPAB */
+ 0x00000004, /* EMC_TCLKSTABLE */
+ 0x00000005, /* EMC_TCLKSTOP */
+ 0x00000c30, /* EMC_TREFBW */
+ 0x00000000, /* EMC_QUSE_EXTRA */
+ 0x00000006, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00007088, /* EMC_FBIO_CFG5 */
+ 0x001d0084, /* EMC_CFG_DIG_DLL */
+ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */
+ 0x00038000, /* EMC_DLL_XFORM_DQS0 */
+ 0x00038000, /* EMC_DLL_XFORM_DQS1 */
+ 0x00038000, /* EMC_DLL_XFORM_DQS2 */
+ 0x00038000, /* EMC_DLL_XFORM_DQS3 */
+ 0x00038000, /* EMC_DLL_XFORM_DQS4 */
+ 0x00038000, /* EMC_DLL_XFORM_DQS5 */
+ 0x00038000, /* EMC_DLL_XFORM_DQS6 */
+ 0x00038000, /* EMC_DLL_XFORM_DQS7 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE3 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE4 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE5 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE6 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE7 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */
+ 0x00030000, /* EMC_DLL_XFORM_DQ0 */
+ 0x00030000, /* EMC_DLL_XFORM_DQ1 */
+ 0x00030000, /* EMC_DLL_XFORM_DQ2 */
+ 0x00030000, /* EMC_DLL_XFORM_DQ3 */
+ 0x000002a0, /* EMC_XM2CMDPADCTRL */
+ 0x0800013d, /* EMC_XM2DQSPADCTRL2 */
+ 0x00000000, /* EMC_XM2DQPADCTRL2 */
+ 0x77fff884, /* EMC_XM2CLKPADCTRL */
+ 0x01f1f508, /* EMC_XM2COMPPADCTRL */
+ 0x05057404, /* EMC_XM2VTTGENPADCTRL */
+ 0x54000007, /* EMC_XM2VTTGENPADCTRL2 */
+ 0x080001e8, /* EMC_XM2QUSEPADCTRL */
+ 0x08000021, /* EMC_XM2DQSPADCTRL3 */
+ 0x00000802, /* EMC_CTT_TERM_CTRL */
+ 0x00020000, /* EMC_ZCAL_INTERVAL */
+ 0x00000100, /* EMC_ZCAL_WAIT_CNT */
+ 0x0158000c, /* EMC_MRS_WAIT_CNT */
+ 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */
+ 0x00000000, /* EMC_CTT */
+ 0x00000000, /* EMC_CTT_DURATION */
+ 0x800018c8, /* EMC_DYN_SELF_REF_CONTROL */
+ 0x00000006, /* MC_EMEM_ARB_CFG */
+ 0x80000048, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RP */
+ 0x00000009, /* MC_EMEM_ARB_TIMING_RC */
+ 0x00000005, /* MC_EMEM_ARB_TIMING_RAS */
+ 0x00000005, /* MC_EMEM_ARB_TIMING_FAW */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */
+ 0x00000008, /* MC_EMEM_ARB_TIMING_WAP2PRE */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_W2W */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_R2W */
+ 0x00000006, /* MC_EMEM_ARB_TIMING_W2R */
+ 0x06030202, /* MC_EMEM_ARB_DA_TURNS */
+ 0x000d0709, /* MC_EMEM_ARB_DA_COVERS */
+ 0x7086120a, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0xe8000000, /* EMC_FBIO_SPARE */
+ 0xff00ff89, /* EMC_CFG_RSV */
+ },
+ 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000000, /* EMC_CFG.PERIODIC_QRST */
+ 0x80000521, /* Mode Register 0 */
+ 0x80100002, /* Mode Register 1 */
+ 0x80200000, /* Mode Register 2 */
+ 0x00000000, /* EMC_CFG.DYN_SELF_REF */
+ },
+ {
+ 0x32, /* Rev 3.2 */
+ 667000, /* SDRAM frequency */
+ {
+ 0x00000023, /* EMC_RC */
+ 0x000000df, /* EMC_RFC */
+ 0x00000019, /* EMC_RAS */
+ 0x00000009, /* EMC_RP */
+ 0x00000005, /* EMC_R2W */
+ 0x0000000d, /* EMC_W2R */
+ 0x00000004, /* EMC_R2P */
+ 0x00000013, /* EMC_W2P */
+ 0x00000009, /* EMC_RD_RCD */
+ 0x00000009, /* EMC_WR_RCD */
+ 0x00000003, /* EMC_RRD */
+ 0x00000001, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000007, /* EMC_WDV */
+ 0x0000000b, /* EMC_QUSE */
+ 0x00000009, /* EMC_QRST */
+ 0x0000000c, /* EMC_QSAFE */
+ 0x00000011, /* EMC_RDV */
+ 0x00001419, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x000005a6, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x00000003, /* EMC_PDEX2WR */
+ 0x00000010, /* EMC_PDEX2RD */
+ 0x00000001, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x0000000e, /* EMC_AR2PDEN */
+ 0x00000018, /* EMC_RW2PDEN */
+ 0x000000e9, /* EMC_TXSR */
+ 0x00000200, /* EMC_TXSRDLL */
+ 0x00000005, /* EMC_TCKE */
+ 0x00000017, /* EMC_TFAW */
+ 0x00000000, /* EMC_TRPAB */
+ 0x00000007, /* EMC_TCLKSTABLE */
+ 0x00000008, /* EMC_TCLKSTOP */
+ 0x000016da, /* EMC_TREFBW */
+ 0x0000000c, /* EMC_QUSE_EXTRA */
+ 0x00000004, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00005088, /* EMC_FBIO_CFG5 */
+ 0xf0080191, /* EMC_CFG_DIG_DLL */
+ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */
+ 0x00000008, /* EMC_DLL_XFORM_DQS0 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS1 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS2 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS3 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS4 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS5 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS6 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS7 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE3 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE4 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE5 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE6 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE7 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */
+ 0x0000000c, /* EMC_DLL_XFORM_DQ0 */
+ 0x0000000c, /* EMC_DLL_XFORM_DQ1 */
+ 0x0000000c, /* EMC_DLL_XFORM_DQ2 */
+ 0x0000000c, /* EMC_DLL_XFORM_DQ3 */
+ 0x000002a0, /* EMC_XM2CMDPADCTRL */
+ 0x0600013d, /* EMC_XM2DQSPADCTRL2 */
+ 0x22220000, /* EMC_XM2DQPADCTRL2 */
+ 0x77fff884, /* EMC_XM2CLKPADCTRL */
+ 0x01f1f501, /* EMC_XM2COMPPADCTRL */
+ 0x07077404, /* EMC_XM2VTTGENPADCTRL */
+ 0x54000000, /* EMC_XM2VTTGENPADCTRL2 */
+ 0x080001e8, /* EMC_XM2QUSEPADCTRL */
+ 0x07000021, /* EMC_XM2DQSPADCTRL3 */
+ 0x00000802, /* EMC_CTT_TERM_CTRL */
+ 0x00020000, /* EMC_ZCAL_INTERVAL */
+ 0x00000100, /* EMC_ZCAL_WAIT_CNT */
+ 0x00df000c, /* EMC_MRS_WAIT_CNT */
+ 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */
+ 0x00000000, /* EMC_CTT */
+ 0x00000000, /* EMC_CTT_DURATION */
+ 0x80002d93, /* EMC_DYN_SELF_REF_CONTROL */
+ 0x0000000b, /* MC_EMEM_ARB_CFG */
+ 0x80000087, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000004, /* MC_EMEM_ARB_TIMING_RCD */
+ 0x00000005, /* MC_EMEM_ARB_TIMING_RP */
+ 0x00000012, /* MC_EMEM_ARB_TIMING_RC */
+ 0x0000000c, /* MC_EMEM_ARB_TIMING_RAS */
+ 0x0000000b, /* MC_EMEM_ARB_TIMING_FAW */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RRD */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_RAP2PRE */
+ 0x0000000c, /* MC_EMEM_ARB_TIMING_WAP2PRE */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_W2W */
+ 0x00000004, /* MC_EMEM_ARB_TIMING_R2W */
+ 0x00000008, /* MC_EMEM_ARB_TIMING_W2R */
+ 0x08040202, /* MC_EMEM_ARB_DA_TURNS */
+ 0x00160d12, /* MC_EMEM_ARB_DA_COVERS */
+ 0x73cc2213, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0xf8000000, /* EMC_FBIO_SPARE */
+ 0xff00ff49, /* EMC_CFG_RSV */
+ },
+ 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000001, /* EMC_CFG.PERIODIC_QRST */
+ 0x80000d71, /* Mode Register 0 */
+ 0x80100002, /* Mode Register 1 */
+ 0x80200018, /* Mode Register 2 */
+ 0x00000000, /* EMC_CFG.DYN_SELF_REF */
+ },
+ {
+ 0x32, /* Rev 3.2 */
750000, /* SDRAM frequency */
{
0x00000023, /* EMC_RC */
@@ -2657,6 +2897,126 @@ static const struct tegra_emc_table cardhu_emc_tables_h5tc2g_a2_2GB1R[] = {
0x80200018, /* Mode Register 2 */
0x00000000, /* EMC_CFG.DYN_SELF_REF */
},
+ {
+ 0x32, /* Rev 3.2 */
+ 800000, /* SDRAM frequency */
+ {
+ 0x00000025, /* EMC_RC */
+ 0x000000ce, /* EMC_RFC */
+ 0x0000001a, /* EMC_RAS */
+ 0x00000009, /* EMC_RP */
+ 0x00000005, /* EMC_R2W */
+ 0x0000000d, /* EMC_W2R */
+ 0x00000004, /* EMC_R2P */
+ 0x00000013, /* EMC_W2P */
+ 0x00000009, /* EMC_RD_RCD */
+ 0x00000009, /* EMC_WR_RCD */
+ 0x00000003, /* EMC_RRD */
+ 0x00000001, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000007, /* EMC_WDV */
+ 0x0000000b, /* EMC_QUSE */
+ 0x00000009, /* EMC_QRST */
+ 0x0000000c, /* EMC_QSAFE */
+ 0x00000012, /* EMC_RDV */
+ 0x00001820, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x00000608, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x00000003, /* EMC_PDEX2WR */
+ 0x00000012, /* EMC_PDEX2RD */
+ 0x00000001, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x0000000f, /* EMC_AR2PDEN */
+ 0x00000018, /* EMC_RW2PDEN */
+ 0x000000d8, /* EMC_TXSR */
+ 0x00000200, /* EMC_TXSRDLL */
+ 0x00000005, /* EMC_TCKE */
+ 0x00000018, /* EMC_TFAW */
+ 0x00000000, /* EMC_TRPAB */
+ 0x00000007, /* EMC_TCLKSTABLE */
+ 0x00000008, /* EMC_TCLKSTOP */
+ 0x00001860, /* EMC_TREFBW */
+ 0x0000000c, /* EMC_QUSE_EXTRA */
+ 0x00000004, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00005088, /* EMC_FBIO_CFG5 */
+ 0xf0070191, /* EMC_CFG_DIG_DLL */
+ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */
+ 0x0000c008, /* EMC_DLL_XFORM_DQS0 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS1 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS2 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS3 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS4 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS5 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS6 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS7 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE3 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE4 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE5 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE6 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE7 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */
+ 0x007f800c, /* EMC_DLL_XFORM_DQ0 */
+ 0x007f800c, /* EMC_DLL_XFORM_DQ1 */
+ 0x007f800c, /* EMC_DLL_XFORM_DQ2 */
+ 0x007f800c, /* EMC_DLL_XFORM_DQ3 */
+ 0x000002a0, /* EMC_XM2CMDPADCTRL */
+ 0x0600013d, /* EMC_XM2DQSPADCTRL2 */
+ 0x22220000, /* EMC_XM2DQPADCTRL2 */
+ 0x77fff884, /* EMC_XM2CLKPADCTRL */
+ 0x01f1f501, /* EMC_XM2COMPPADCTRL */
+ 0x07077404, /* EMC_XM2VTTGENPADCTRL */
+ 0x54000000, /* EMC_XM2VTTGENPADCTRL2 */
+ 0x080001e8, /* EMC_XM2QUSEPADCTRL */
+ 0x07000021, /* EMC_XM2DQSPADCTRL3 */
+ 0x00000802, /* EMC_CTT_TERM_CTRL */
+ 0x00020000, /* EMC_ZCAL_INTERVAL */
+ 0x00000100, /* EMC_ZCAL_WAIT_CNT */
+ 0x00f0000c, /* EMC_MRS_WAIT_CNT */
+ 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */
+ 0x00000000, /* EMC_CTT */
+ 0x00000000, /* EMC_CTT_DURATION */
+ 0x8000308c, /* EMC_DYN_SELF_REF_CONTROL */
+ 0x0000000c, /* MC_EMEM_ARB_CFG */
+ 0x80000090, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000004, /* MC_EMEM_ARB_TIMING_RCD */
+ 0x00000005, /* MC_EMEM_ARB_TIMING_RP */
+ 0x00000013, /* MC_EMEM_ARB_TIMING_RC */
+ 0x0000000c, /* MC_EMEM_ARB_TIMING_RAS */
+ 0x0000000b, /* MC_EMEM_ARB_TIMING_FAW */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RRD */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_RAP2PRE */
+ 0x0000000c, /* MC_EMEM_ARB_TIMING_WAP2PRE */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_W2W */
+ 0x00000004, /* MC_EMEM_ARB_TIMING_R2W */
+ 0x00000008, /* MC_EMEM_ARB_TIMING_W2R */
+ 0x08040202, /* MC_EMEM_ARB_DA_TURNS */
+ 0x00160d13, /* MC_EMEM_ARB_DA_COVERS */
+ 0x712c2414, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0xf8000000, /* EMC_FBIO_SPARE */
+ 0xff00ff49, /* EMC_CFG_RSV */
+ },
+ 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000001, /* EMC_CFG.PERIODIC_QRST */
+ 0x80000d71, /* Mode Register 0 */
+ 0x80100002, /* Mode Register 1 */
+ 0x80200018, /* Mode Register 2 */
+ 0x00000000, /* EMC_CFG.DYN_SELF_REF */
+ },
};
static const struct tegra_emc_table cardhu_emc_tables_k4b4g0846b_hyk0[] = {
@@ -3625,6 +3985,126 @@ static const struct tegra_emc_table cardhu_emc_tables_k4b4g0846b_hyk0[] = {
static const struct tegra_emc_table cardhu_emc_tables_k4p8g304eb[] = {
{
0x32, /* Rev 3.2 */
+ 12750, /* SDRAM frequency */
+ {
+ 0x00000000, /* EMC_RC */
+ 0x00000001, /* EMC_RFC */
+ 0x00000002, /* EMC_RAS */
+ 0x00000002, /* EMC_RP */
+ 0x00000004, /* EMC_R2W */
+ 0x00000004, /* EMC_W2R */
+ 0x00000001, /* EMC_R2P */
+ 0x00000005, /* EMC_W2P */
+ 0x00000002, /* EMC_RD_RCD */
+ 0x00000002, /* EMC_WR_RCD */
+ 0x00000001, /* EMC_RRD */
+ 0x00000001, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000001, /* EMC_WDV */
+ 0x00000003, /* EMC_QUSE */
+ 0x00000001, /* EMC_QRST */
+ 0x00000009, /* EMC_QSAFE */
+ 0x0000000a, /* EMC_RDV */
+ 0x0000002f, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x0000000b, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x00000001, /* EMC_PDEX2WR */
+ 0x00000001, /* EMC_PDEX2RD */
+ 0x00000002, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x00000001, /* EMC_AR2PDEN */
+ 0x00000007, /* EMC_RW2PDEN */
+ 0x00000002, /* EMC_TXSR */
+ 0x00000002, /* EMC_TXSRDLL */
+ 0x00000003, /* EMC_TCKE */
+ 0x00000008, /* EMC_TFAW */
+ 0x00000004, /* EMC_TRPAB */
+ 0x00000004, /* EMC_TCLKSTABLE */
+ 0x00000002, /* EMC_TCLKSTOP */
+ 0x00000036, /* EMC_TREFBW */
+ 0x00000004, /* EMC_QUSE_EXTRA */
+ 0x00000004, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00004282, /* EMC_FBIO_CFG5 */
+ 0x007800a4, /* EMC_CFG_DIG_DLL */
+ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS0 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS1 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS2 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS3 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS4 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS5 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS6 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS7 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE3 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE4 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE5 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE6 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE7 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQ0 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQ1 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQ2 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQ3 */
+ 0x00100220, /* EMC_XM2CMDPADCTRL */
+ 0x0800201c, /* EMC_XM2DQSPADCTRL2 */
+ 0x00000000, /* EMC_XM2DQPADCTRL2 */
+ 0x77ffc004, /* EMC_XM2CLKPADCTRL */
+ 0x01f1f008, /* EMC_XM2COMPPADCTRL */
+ 0x00000000, /* EMC_XM2VTTGENPADCTRL */
+ 0x00000007, /* EMC_XM2VTTGENPADCTRL2 */
+ 0x08000068, /* EMC_XM2QUSEPADCTRL */
+ 0x08000000, /* EMC_XM2DQSPADCTRL3 */
+ 0x00000802, /* EMC_CTT_TERM_CTRL */
+ 0x00064000, /* EMC_ZCAL_INTERVAL */
+ 0x00000009, /* EMC_ZCAL_WAIT_CNT */
+ 0x00090009, /* EMC_MRS_WAIT_CNT */
+ 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */
+ 0x00000000, /* EMC_CTT */
+ 0x00000000, /* EMC_CTT_DURATION */
+ 0x80000164, /* EMC_DYN_SELF_REF_CONTROL */
+ 0x00020001, /* MC_EMEM_ARB_CFG */
+ 0xc0000010, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RP */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RC */
+ 0x00000000, /* MC_EMEM_ARB_TIMING_RAS */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_FAW */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */
+ 0x00000004, /* MC_EMEM_ARB_TIMING_WAP2PRE */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_R2R */
+ 0x00000000, /* MC_EMEM_ARB_TIMING_W2W */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_R2W */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_W2R */
+ 0x02020001, /* MC_EMEM_ARB_DA_TURNS */
+ 0x00060402, /* MC_EMEM_ARB_DA_COVERS */
+ 0x77230303, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0xd0000000, /* EMC_FBIO_SPARE */
+ 0xff00ff00, /* EMC_CFG_RSV */
+ },
+ 0x00000009, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000001, /* EMC_CFG.PERIODIC_QRST */
+ 0x00000000, /* Mode Register 0 */
+ 0x00010022, /* Mode Register 1 */
+ 0x00020001, /* Mode Register 2 */
+ 0x00000001, /* EMC_CFG.DYN_SELF_REF */
+ },
+ {
+ 0x32, /* Rev 3.2 */
25500, /* SDRAM frequency */
{
0x00000001, /* EMC_RC */
@@ -4105,6 +4585,246 @@ static const struct tegra_emc_table cardhu_emc_tables_k4p8g304eb[] = {
},
{
0x32, /* Rev 3.2 */
+ 266500, /* SDRAM frequency */
+ {
+ 0x0000000f, /* EMC_RC */
+ 0x00000022, /* EMC_RFC */
+ 0x0000000b, /* EMC_RAS */
+ 0x00000004, /* EMC_RP */
+ 0x00000005, /* EMC_R2W */
+ 0x00000005, /* EMC_W2R */
+ 0x00000001, /* EMC_R2P */
+ 0x00000007, /* EMC_W2P */
+ 0x00000004, /* EMC_RD_RCD */
+ 0x00000004, /* EMC_WR_RCD */
+ 0x00000002, /* EMC_RRD */
+ 0x00000002, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000002, /* EMC_WDV */
+ 0x00000005, /* EMC_QUSE */
+ 0x00000002, /* EMC_QRST */
+ 0x0000000c, /* EMC_QSAFE */
+ 0x0000000b, /* EMC_RDV */
+ 0x000003ef, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x000000fb, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x00000001, /* EMC_PDEX2WR */
+ 0x00000001, /* EMC_PDEX2RD */
+ 0x00000004, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x00000001, /* EMC_AR2PDEN */
+ 0x00000009, /* EMC_RW2PDEN */
+ 0x00000026, /* EMC_TXSR */
+ 0x00000026, /* EMC_TXSRDLL */
+ 0x00000004, /* EMC_TCKE */
+ 0x0000000e, /* EMC_TFAW */
+ 0x00000006, /* EMC_TRPAB */
+ 0x00000001, /* EMC_TCLKSTABLE */
+ 0x00000002, /* EMC_TCLKSTOP */
+ 0x00000455, /* EMC_TREFBW */
+ 0x00000000, /* EMC_QUSE_EXTRA */
+ 0x00000004, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00006282, /* EMC_FBIO_CFG5 */
+ 0x003200a4, /* EMC_CFG_DIG_DLL */
+ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */
+ 0x00060000, /* EMC_DLL_XFORM_DQS0 */
+ 0x00060000, /* EMC_DLL_XFORM_DQS1 */
+ 0x00060000, /* EMC_DLL_XFORM_DQS2 */
+ 0x00060000, /* EMC_DLL_XFORM_DQS3 */
+ 0x00060000, /* EMC_DLL_XFORM_DQS4 */
+ 0x00060000, /* EMC_DLL_XFORM_DQS5 */
+ 0x00060000, /* EMC_DLL_XFORM_DQS6 */
+ 0x00060000, /* EMC_DLL_XFORM_DQS7 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE3 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE4 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE5 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE6 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE7 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */
+ 0x00068000, /* EMC_DLL_XFORM_DQ0 */
+ 0x00068000, /* EMC_DLL_XFORM_DQ1 */
+ 0x00068000, /* EMC_DLL_XFORM_DQ2 */
+ 0x00068000, /* EMC_DLL_XFORM_DQ3 */
+ 0x000a0220, /* EMC_XM2CMDPADCTRL */
+ 0x0800003d, /* EMC_XM2DQSPADCTRL2 */
+ 0x00000000, /* EMC_XM2DQPADCTRL2 */
+ 0x77ffc004, /* EMC_XM2CLKPADCTRL */
+ 0x01f1f008, /* EMC_XM2COMPPADCTRL */
+ 0x00000000, /* EMC_XM2VTTGENPADCTRL */
+ 0x00000007, /* EMC_XM2VTTGENPADCTRL2 */
+ 0x08000068, /* EMC_XM2QUSEPADCTRL */
+ 0x08000000, /* EMC_XM2DQSPADCTRL3 */
+ 0x00000802, /* EMC_CTT_TERM_CTRL */
+ 0x00064000, /* EMC_ZCAL_INTERVAL */
+ 0x00000060, /* EMC_ZCAL_WAIT_CNT */
+ 0x000a000a, /* EMC_MRS_WAIT_CNT */
+ 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */
+ 0x00000000, /* EMC_CTT */
+ 0x00000000, /* EMC_CTT_DURATION */
+ 0x800008ee, /* EMC_DYN_SELF_REF_CONTROL */
+ 0x00000004, /* MC_EMEM_ARB_CFG */
+ 0x80000030, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RP */
+ 0x00000008, /* MC_EMEM_ARB_TIMING_RC */
+ 0x00000004, /* MC_EMEM_ARB_TIMING_RAS */
+ 0x00000006, /* MC_EMEM_ARB_TIMING_FAW */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */
+ 0x00000005, /* MC_EMEM_ARB_TIMING_WAP2PRE */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_R2R */
+ 0x00000000, /* MC_EMEM_ARB_TIMING_W2W */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_R2W */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_W2R */
+ 0x03030001, /* MC_EMEM_ARB_DA_TURNS */
+ 0x00090608, /* MC_EMEM_ARB_DA_COVERS */
+ 0x70040c09, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0xe0000000, /* EMC_FBIO_SPARE */
+ 0xff00ff00, /* EMC_CFG_RSV */
+ },
+ 0x00000018, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000001, /* EMC_CFG.PERIODIC_QRST */
+ 0x00000000, /* Mode Register 0 */
+ 0x00010042, /* Mode Register 1 */
+ 0x00020002, /* Mode Register 2 */
+ 0x00000000, /* EMC_CFG.DYN_SELF_REF */
+ },
+ {
+ 0x32, /* Rev 3.2 */
+ 437000, /* SDRAM frequency */
+ {
+ 0x0000001a, /* EMC_RC */
+ 0x00000038, /* EMC_RFC */
+ 0x00000012, /* EMC_RAS */
+ 0x00000007, /* EMC_RP */
+ 0x00000007, /* EMC_R2W */
+ 0x00000009, /* EMC_W2R */
+ 0x00000003, /* EMC_R2P */
+ 0x0000000c, /* EMC_W2P */
+ 0x00000007, /* EMC_RD_RCD */
+ 0x00000007, /* EMC_WR_RCD */
+ 0x00000004, /* EMC_RRD */
+ 0x00000002, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000004, /* EMC_WDV */
+ 0x00000008, /* EMC_QUSE */
+ 0x00000005, /* EMC_QRST */
+ 0x0000000d, /* EMC_QSAFE */
+ 0x0000000f, /* EMC_RDV */
+ 0x00000674, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x0000019d, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x00000003, /* EMC_PDEX2WR */
+ 0x00000003, /* EMC_PDEX2RD */
+ 0x00000007, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x00000001, /* EMC_AR2PDEN */
+ 0x0000000d, /* EMC_RW2PDEN */
+ 0x0000003e, /* EMC_TXSR */
+ 0x0000003e, /* EMC_TXSRDLL */
+ 0x00000007, /* EMC_TCKE */
+ 0x00000016, /* EMC_TFAW */
+ 0x0000000a, /* EMC_TRPAB */
+ 0x00000004, /* EMC_TCLKSTABLE */
+ 0x00000002, /* EMC_TCLKSTOP */
+ 0x0000071a, /* EMC_TREFBW */
+ 0x00000000, /* EMC_QUSE_EXTRA */
+ 0x00000004, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00006282, /* EMC_FBIO_CFG5 */
+ 0x00190084, /* EMC_CFG_DIG_DLL */
+ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */
+ 0x00014000, /* EMC_DLL_XFORM_DQS0 */
+ 0x00014000, /* EMC_DLL_XFORM_DQS1 */
+ 0x00014000, /* EMC_DLL_XFORM_DQS2 */
+ 0x00014000, /* EMC_DLL_XFORM_DQS3 */
+ 0x00014000, /* EMC_DLL_XFORM_DQS4 */
+ 0x00014000, /* EMC_DLL_XFORM_DQS5 */
+ 0x00014000, /* EMC_DLL_XFORM_DQS6 */
+ 0x00014000, /* EMC_DLL_XFORM_DQS7 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE3 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE4 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE5 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE6 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE7 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */
+ 0x00038000, /* EMC_DLL_XFORM_DQ0 */
+ 0x00038000, /* EMC_DLL_XFORM_DQ1 */
+ 0x00038000, /* EMC_DLL_XFORM_DQ2 */
+ 0x00038000, /* EMC_DLL_XFORM_DQ3 */
+ 0x00080220, /* EMC_XM2CMDPADCTRL */
+ 0x0800003d, /* EMC_XM2DQSPADCTRL2 */
+ 0x00000000, /* EMC_XM2DQPADCTRL2 */
+ 0x77ffe004, /* EMC_XM2CLKPADCTRL */
+ 0x01f1f408, /* EMC_XM2COMPPADCTRL */
+ 0x00000000, /* EMC_XM2VTTGENPADCTRL */
+ 0x00000007, /* EMC_XM2VTTGENPADCTRL2 */
+ 0x08000068, /* EMC_XM2QUSEPADCTRL */
+ 0x08000000, /* EMC_XM2DQSPADCTRL3 */
+ 0x00000802, /* EMC_CTT_TERM_CTRL */
+ 0x00064000, /* EMC_ZCAL_INTERVAL */
+ 0x0000009e, /* EMC_ZCAL_WAIT_CNT */
+ 0x000d000d, /* EMC_MRS_WAIT_CNT */
+ 0xa0f10202, /* EMC_AUTO_CAL_CONFIG */
+ 0x00000000, /* EMC_CTT */
+ 0x00000000, /* EMC_CTT_DURATION */
+ 0x80000dff, /* EMC_DYN_SELF_REF_CONTROL */
+ 0x00000006, /* MC_EMEM_ARB_CFG */
+ 0xc000004f, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RCD */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_RP */
+ 0x0000000d, /* MC_EMEM_ARB_TIMING_RC */
+ 0x00000008, /* MC_EMEM_ARB_TIMING_RAS */
+ 0x0000000a, /* MC_EMEM_ARB_TIMING_FAW */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RRD */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */
+ 0x00000007, /* MC_EMEM_ARB_TIMING_WAP2PRE */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_R2R */
+ 0x00000000, /* MC_EMEM_ARB_TIMING_W2W */
+ 0x00000004, /* MC_EMEM_ARB_TIMING_R2W */
+ 0x00000005, /* MC_EMEM_ARB_TIMING_W2R */
+ 0x05040001, /* MC_EMEM_ARB_DA_TURNS */
+ 0x000e090d, /* MC_EMEM_ARB_DA_COVERS */
+ 0x7027140e, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0xe0000000, /* EMC_FBIO_SPARE */
+ 0xff00ff88, /* EMC_CFG_RSV */
+ },
+ 0x00000028, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000001, /* EMC_CFG.PERIODIC_QRST */
+ 0x00000000, /* Mode Register 0 */
+ 0x000100a2, /* Mode Register 1 */
+ 0x00020005, /* Mode Register 2 */
+ 0x00000000, /* EMC_CFG.DYN_SELF_REF */
+ },
+ {
+ 0x32, /* Rev 3.2 */
533000, /* SDRAM frequency */
{
0x0000001f, /* EMC_RC */
diff --git a/arch/arm/mach-tegra/board-cardhu-panel.c b/arch/arm/mach-tegra/board-cardhu-panel.c
index aaec711677fb..6fa33f919dad 100644
--- a/arch/arm/mach-tegra/board-cardhu-panel.c
+++ b/arch/arm/mach-tegra/board-cardhu-panel.c
@@ -30,7 +30,7 @@
#include <linux/pwm_backlight.h>
#include <asm/atomic.h>
#include <linux/nvhost.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include <mach/irqs.h>
#include <mach/iomap.h>
#include <mach/dc.h>
@@ -41,10 +41,11 @@
#include "board-cardhu.h"
#include "devices.h"
#include "gpio-names.h"
+#include "tegra3_host1x_devices.h"
+
+#define DC_CTRL_MODE (TEGRA_DC_OUT_ONE_SHOT_MODE | \
+ TEGRA_DC_OUT_ONE_SHOT_LP_MODE)
-/* Select panel to be used. */
-#define DSI_PANEL_219 1
-#define DSI_PANEL_218 0
#define AVDD_LCD PMU_TCA6416_GPIO_PORT17
#define DSI_PANEL_RESET 1
@@ -58,7 +59,14 @@
#define pm313_MODE0 TEGRA_GPIO_PZ4
#define pm313_MODE1 TEGRA_GPIO_PW1
#define pm313_BPP TEGRA_GPIO_PN6 /* 0:24bpp, 1:18bpp */
-#define pm313_lvds_shutdown TEGRA_GPIO_PH1
+#define pm313_lvds_shutdown TEGRA_GPIO_PL2
+
+/* E1506 display board pins */
+#define e1506_lcd_te TEGRA_GPIO_PJ1
+#define e1506_dsi_vddio TEGRA_GPIO_PH1
+#define e1506_dsia_bl_pwm TEGRA_GPIO_PH0
+#define e1506_panel_enb TEGRA_GPIO_PW1
+#define e1506_bl_enb TEGRA_GPIO_PH2
/* E1247 reworked for pm269 pins */
#define e1247_pm269_lvds_shutdown TEGRA_GPIO_PN6
@@ -71,12 +79,11 @@
#define cardhu_bl_pwm TEGRA_GPIO_PH0
#define cardhu_hdmi_hpd TEGRA_GPIO_PN7
-#if defined(DSI_PANEL_219) || defined(DSI_PANEL_218)
+/* common dsi panel pins */
#define cardhu_dsia_bl_enb TEGRA_GPIO_PW1
#define cardhu_dsib_bl_enb TEGRA_GPIO_PW0
-#define cardhu_dsi_218_panel_reset TEGRA_GPIO_PD2
-#define cardhu_dsi_219_panel_reset TEGRA_GPIO_PW0
-#endif
+#define cardhu_dsi_pnl_reset TEGRA_GPIO_PD2
+#define cardhu_dsi_219_pnl_reset TEGRA_GPIO_PW0
#ifdef CONFIG_TEGRA_DC
static struct regulator *cardhu_hdmi_reg = NULL;
@@ -86,13 +93,10 @@ static struct regulator *cardhu_hdmi_vddio = NULL;
static atomic_t sd_brightness = ATOMIC_INIT(255);
-#ifdef CONFIG_TEGRA_CARDHU_DSI
static struct regulator *cardhu_dsi_reg = NULL;
-#else
static struct regulator *cardhu_lvds_reg = NULL;
static struct regulator *cardhu_lvds_vdd_bl = NULL;
static struct regulator *cardhu_lvds_vdd_panel = NULL;
-#endif
static struct board_info board_info;
static struct board_info display_board_info;
@@ -132,127 +136,112 @@ static tegra_dc_bl_output cardhu_bl_output_measured = {
248, 249, 250, 251, 252, 253, 254, 255
};
-static p_tegra_dc_bl_output bl_output;
+static p_tegra_dc_bl_output bl_output = cardhu_bl_output_measured;
-static int cardhu_backlight_init(struct device *dev)
+static bool is_panel_218;
+static bool is_panel_219;
+static bool is_panel_1506;
+
+static bool is_dsi_panel(void)
{
- int ret;
+ return is_panel_218 || is_panel_219 || is_panel_1506;
+}
- bl_output = cardhu_bl_output_measured;
+static int cardhu_backlight_init(struct device *dev)
+{
+ int ret = 0;
if (WARN_ON(ARRAY_SIZE(cardhu_bl_output_measured) != 256))
pr_err("bl_output array does not have 256 elements\n");
-#ifndef CONFIG_TEGRA_CARDHU_DSI
- tegra_gpio_disable(cardhu_bl_pwm);
-
- ret = gpio_request(cardhu_bl_enb, "backlight_enb");
- if (ret < 0)
- return ret;
-
- ret = gpio_direction_output(cardhu_bl_enb, 1);
- if (ret < 0)
- gpio_free(cardhu_bl_enb);
- else
- tegra_gpio_enable(cardhu_bl_enb);
-
- return ret;
-#endif
-
-#if DSI_PANEL_218
- /* Enable back light for DSIa panel */
- ret = gpio_request(cardhu_dsia_bl_enb, "dsia_bl_enable");
- if (ret < 0)
- return ret;
+ if (!is_dsi_panel()) {
+ ret = gpio_request(cardhu_bl_enb, "backlight_enb");
+ if (ret < 0)
+ return ret;
- ret = gpio_direction_output(cardhu_dsia_bl_enb, 1);
- if (ret < 0)
- gpio_free(cardhu_dsia_bl_enb);
- else
- tegra_gpio_enable(cardhu_dsia_bl_enb);
+ ret = gpio_direction_output(cardhu_bl_enb, 1);
+ if (ret < 0)
+ gpio_free(cardhu_bl_enb);
+ } else if (is_panel_218) {
+ /* Enable back light for DSIa panel */
+ ret = gpio_request(cardhu_dsia_bl_enb, "dsia_bl_enable");
+ if (ret < 0)
+ return ret;
- /* Enable back light for DSIb panel */
- ret = gpio_request(cardhu_dsib_bl_enb, "dsib_bl_enable");
- if (ret < 0)
- return ret;
+ ret = gpio_direction_output(cardhu_dsia_bl_enb, 1);
+ if (ret < 0)
+ gpio_free(cardhu_dsia_bl_enb);
- ret = gpio_direction_output(cardhu_dsib_bl_enb, 1);
- if (ret < 0)
- gpio_free(cardhu_dsib_bl_enb);
- else
- tegra_gpio_enable(cardhu_dsib_bl_enb);
-#endif
+ /* Enable back light for DSIb panel */
+ ret = gpio_request(cardhu_dsib_bl_enb, "dsib_bl_enable");
+ if (ret < 0)
+ return ret;
-#if DSI_PANEL_219
- /* Enable back light for DSIa panel */
- ret = gpio_request(cardhu_dsia_bl_enb, "dsia_bl_enable");
- if (ret < 0)
- return ret;
+ ret = gpio_direction_output(cardhu_dsib_bl_enb, 1);
+ if (ret < 0)
+ gpio_free(cardhu_dsib_bl_enb);
+ } else if (is_panel_219) {
+ /* Enable back light for DSIa panel */
+ ret = gpio_request(cardhu_dsia_bl_enb, "dsia_bl_enable");
+ if (ret < 0)
+ return ret;
- ret = gpio_direction_output(cardhu_dsia_bl_enb, 1);
- if (ret < 0)
- gpio_free(cardhu_dsia_bl_enb);
- else
- tegra_gpio_enable(cardhu_dsia_bl_enb);
-#endif
+ ret = gpio_direction_output(cardhu_dsia_bl_enb, 1);
+ if (ret < 0)
+ gpio_free(cardhu_dsia_bl_enb);
+ }
return ret;
};
static void cardhu_backlight_exit(struct device *dev)
{
-#ifndef CONFIG_TEGRA_CARDHU_DSI
- /* int ret; */
- /*ret = gpio_request(cardhu_bl_enb, "backlight_enb");*/
- gpio_set_value(cardhu_bl_enb, 0);
- gpio_free(cardhu_bl_enb);
- tegra_gpio_disable(cardhu_bl_enb);
- return;
-#endif
-
-#if DSI_PANEL_218
- /* Disable back light for DSIa panel */
- gpio_set_value(cardhu_dsia_bl_enb, 0);
- gpio_free(cardhu_dsia_bl_enb);
- tegra_gpio_disable(cardhu_dsia_bl_enb);
-
- /* Disable back light for DSIb panel */
- gpio_set_value(cardhu_dsib_bl_enb, 0);
- gpio_free(cardhu_dsib_bl_enb);
- tegra_gpio_disable(cardhu_dsib_bl_enb);
+ if (!is_dsi_panel()) {
+ /* int ret; */
+ /*ret = gpio_request(cardhu_bl_enb, "backlight_enb");*/
+ gpio_set_value(cardhu_bl_enb, 0);
+ gpio_free(cardhu_bl_enb);
+ } else if (is_panel_218) {
+ /* Disable back light for DSIa panel */
+ gpio_set_value(cardhu_dsia_bl_enb, 0);
+ gpio_free(cardhu_dsia_bl_enb);
- gpio_set_value(cardhu_lvds_shutdown, 1);
- mdelay(20);
-#endif
+ /* Disable back light for DSIb panel */
+ gpio_set_value(cardhu_dsib_bl_enb, 0);
+ gpio_free(cardhu_dsib_bl_enb);
-#if DSI_PANEL_219
- /* Disable back light for DSIa panel */
- gpio_set_value(cardhu_dsia_bl_enb, 0);
- gpio_free(cardhu_dsia_bl_enb);
- tegra_gpio_disable(cardhu_dsia_bl_enb);
+ gpio_set_value(cardhu_lvds_shutdown, 1);
+ mdelay(20);
+ } else if (is_panel_219) {
+ /* Disable back light for DSIa panel */
+ gpio_set_value(cardhu_dsia_bl_enb, 0);
+ gpio_free(cardhu_dsia_bl_enb);
- gpio_set_value(cardhu_lvds_shutdown, 1);
- mdelay(20);
-#endif
+ gpio_set_value(cardhu_lvds_shutdown, 1);
+ mdelay(20);
+ }
}
static int cardhu_backlight_notify(struct device *unused, int brightness)
{
int cur_sd_brightness = atomic_read(&sd_brightness);
-#ifndef CONFIG_TEGRA_CARDHU_DSI
- /* Set the backlight GPIO pin mode to 'backlight_enable' */
- gpio_set_value(cardhu_bl_enb, !!brightness);
-#elif DSI_PANEL_218
- /* DSIa */
- gpio_set_value(cardhu_dsia_bl_enb, !!brightness);
-
- /* DSIb */
- gpio_set_value(cardhu_dsib_bl_enb, !!brightness);
-#elif DSI_PANEL_219
- /* DSIa */
- gpio_set_value(cardhu_dsia_bl_enb, !!brightness);
-#endif
+ if (!is_dsi_panel()) {
+ /* Set the backlight GPIO pin mode to 'backlight_enable' */
+ gpio_set_value(cardhu_bl_enb, !!brightness);
+ } else if (is_panel_218) {
+ /* DSIa */
+ gpio_set_value(cardhu_dsia_bl_enb, !!brightness);
+
+ /* DSIb */
+ gpio_set_value(cardhu_dsib_bl_enb, !!brightness);
+ } else if (is_panel_219) {
+ /* DSIa */
+ gpio_set_value(cardhu_dsia_bl_enb, !!brightness);
+ } else if (is_panel_1506) {
+ /* DSIa */
+ gpio_set_value(e1506_bl_enb, !!brightness);
+ }
/* SD brightness is a percentage, 8-bit value. */
brightness = (brightness * cur_sd_brightness) / 255;
@@ -261,13 +250,7 @@ static int cardhu_backlight_notify(struct device *unused, int brightness)
if (brightness > 255) {
pr_info("Error: Brightness > 255!\n");
} else {
- /* This value depends on the panel.
- Current 19X12 panel with PM313 gets
- full brightness when the output is 0. */
- if (display_board_info.board_id == BOARD_DISPLAY_PM313)
- brightness = 255 - bl_output[brightness];
- else
- brightness = bl_output[brightness];
+ brightness = bl_output[brightness];
}
return brightness;
@@ -295,7 +278,6 @@ static struct platform_device cardhu_backlight_device = {
},
};
-#ifndef CONFIG_TEGRA_CARDHU_DSI
static int cardhu_panel_enable(void)
{
if (cardhu_lvds_reg == NULL) {
@@ -377,7 +359,6 @@ static int cardhu_panel_disable(void)
}
return 0;
}
-#endif
#ifdef CONFIG_TEGRA_DC
static int cardhu_hdmi_vddio_enable(void)
@@ -522,7 +503,6 @@ static struct resource cardhu_disp2_resources[] = {
};
#endif
-#ifndef CONFIG_TEGRA_CARDHU_DSI
static struct tegra_dc_mode panel_19X12_modes[] = {
{
.pclk = 154000000,
@@ -600,7 +580,6 @@ static struct tegra_dc_mode cardhu_panel_modes_55hz[] = {
.v_front_porch = 25,
},
};
-#endif
static struct tegra_dc_sd_settings cardhu_sd_settings = {
.enable = 1, /* enabled by default. */
@@ -695,7 +674,6 @@ static struct tegra_dc_sd_settings cardhu_sd_settings = {
};
#ifdef CONFIG_TEGRA_DC
-#ifndef CONFIG_TEGRA_CARDHU_DSI
static struct tegra_fb_data cardhu_fb_data = {
.win = 0,
.xres = 1366,
@@ -703,7 +681,6 @@ static struct tegra_fb_data cardhu_fb_data = {
.bits_per_pixel = 32,
.flags = TEGRA_FB_FLIP_ON_PROBE,
};
-#endif
static struct tegra_fb_data cardhu_hdmi_fb_data = {
.win = 0,
@@ -741,7 +718,6 @@ static struct tegra_dc_platform_data cardhu_disp2_pdata = {
};
#endif
-#ifdef CONFIG_TEGRA_CARDHU_DSI
static int cardhu_dsi_panel_enable(void)
{
int ret;
@@ -754,86 +730,130 @@ static int cardhu_dsi_panel_enable(void)
return PTR_ERR(cardhu_dsi_reg);
}
}
+
regulator_enable(cardhu_dsi_reg);
- ret = gpio_request(AVDD_LCD, "avdd_lcd");
- if (ret < 0)
- gpio_free(AVDD_LCD);
- ret = gpio_direction_output(AVDD_LCD, 1);
- if (ret < 0)
- gpio_free(AVDD_LCD);
- else
- tegra_gpio_enable(AVDD_LCD);
+ if (!is_panel_1506) {
+ ret = gpio_request(AVDD_LCD, "avdd_lcd");
+ if (ret < 0)
+ gpio_free(AVDD_LCD);
+ ret = gpio_direction_output(AVDD_LCD, 1);
+ if (ret < 0)
+ gpio_free(AVDD_LCD);
+ }
-#if DSI_PANEL_219
+ if (is_panel_219) {
+ ret = gpio_request(cardhu_bl_pwm, "bl_pwm");
+ if (ret < 0)
+ return ret;
+ ret = gpio_direction_output(cardhu_bl_pwm, 0);
+ if (ret < 0) {
+ gpio_free(cardhu_bl_pwm);
+ return ret;
+ }
- ret = gpio_request(cardhu_bl_pwm, "bl_pwm");
- if (ret < 0)
- return ret;
- ret = gpio_direction_output(cardhu_bl_pwm, 0);
- if (ret < 0) {
- gpio_free(cardhu_bl_pwm);
- return ret;
- } else
- tegra_gpio_enable(cardhu_bl_pwm);
+ ret = gpio_request(cardhu_bl_enb, "bl_enb");
+ if (ret < 0)
+ return ret;
+ ret = gpio_direction_output(cardhu_bl_enb, 0);
+ if (ret < 0) {
+ gpio_free(cardhu_bl_enb);
+ return ret;
+ }
- ret = gpio_request(cardhu_bl_enb, "bl_enb");
- if (ret < 0)
- return ret;
- ret = gpio_direction_output(cardhu_bl_enb, 0);
- if (ret < 0) {
- gpio_free(cardhu_bl_enb);
- return ret;
- } else
- tegra_gpio_enable(cardhu_bl_enb);
-
- gpio_set_value(cardhu_lvds_shutdown, 1);
- mdelay(20);
- gpio_set_value(cardhu_bl_pwm, 1);
- mdelay(10);
- gpio_set_value(cardhu_bl_enb, 1);
- mdelay(15);
-#endif
+ gpio_set_value(cardhu_lvds_shutdown, 1);
+ mdelay(20);
+ gpio_set_value(cardhu_bl_pwm, 1);
+ mdelay(10);
+ gpio_set_value(cardhu_bl_enb, 1);
+ mdelay(15);
+ } else if (is_panel_1506) {
+ ret = gpio_request(e1506_dsi_vddio, "e1506_dsi_vddio");
+ if (ret < 0)
+ return ret;
+ ret = gpio_direction_output(e1506_dsi_vddio, 0);
+ if (ret < 0) {
+ gpio_free(e1506_dsi_vddio);
+ return ret;
+ }
-#if DSI_PANEL_RESET
-#if DSI_PANEL_218
- ret = gpio_request(cardhu_dsi_218_panel_reset, "dsi_panel_reset");
- if (ret < 0) {
- return ret;
+ ret = gpio_request(e1506_panel_enb, "e1506_panel_enb");
+ if (ret < 0)
+ return ret;
+ ret = gpio_direction_output(e1506_panel_enb, 0);
+ if (ret < 0) {
+ gpio_free(e1506_panel_enb);
+ return ret;
+ }
+
+ ret = gpio_request(e1506_bl_enb, "e1506_bl_enb");
+ if (ret < 0)
+ return ret;
+ ret = gpio_direction_output(e1506_bl_enb, 0);
+ if (ret < 0) {
+ gpio_free(e1506_bl_enb);
+ return ret;
+ }
+
+ gpio_set_value(e1506_dsi_vddio, 1);
+ mdelay(1);
+ gpio_set_value(e1506_panel_enb, 1);
+ mdelay(10);
+ gpio_set_value(e1506_bl_enb, 1);
+ mdelay(15);
}
- ret = gpio_direction_output(cardhu_dsi_218_panel_reset, 0);
- if (ret < 0) {
- gpio_free(cardhu_dsi_218_panel_reset);
- return ret;
- } else
- tegra_gpio_enable(cardhu_dsi_218_panel_reset);
-
- gpio_set_value(cardhu_dsi_218_panel_reset, 1);
- gpio_set_value(cardhu_dsi_218_panel_reset, 0);
- mdelay(2);
- gpio_set_value(cardhu_dsi_218_panel_reset, 1);
- mdelay(2);
-#endif
-#if DSI_PANEL_219
- ret = gpio_request(cardhu_dsi_219_panel_reset, "dsi_panel_reset");
- if (ret < 0)
- return ret;
- ret = gpio_direction_output(cardhu_dsi_219_panel_reset, 0);
- if (ret < 0) {
- gpio_free(cardhu_dsi_219_panel_reset);
- return ret;
- } else
- tegra_gpio_enable(cardhu_dsi_219_panel_reset);
-
- gpio_set_value(cardhu_dsi_219_panel_reset, 0);
- gpio_set_value(cardhu_dsi_219_panel_reset, 1);
- mdelay(10);
- gpio_set_value(cardhu_dsi_219_panel_reset, 0);
- mdelay(10);
- gpio_set_value(cardhu_dsi_219_panel_reset, 1);
- mdelay(15);
-#endif
+#if DSI_PANEL_RESET
+ if (is_panel_218) {
+ ret = gpio_request(cardhu_dsi_pnl_reset, "dsi_panel_reset");
+ if (ret < 0)
+ return ret;
+
+ ret = gpio_direction_output(cardhu_dsi_pnl_reset, 0);
+ if (ret < 0) {
+ gpio_free(cardhu_dsi_pnl_reset);
+ return ret;
+ }
+
+ gpio_set_value(cardhu_dsi_pnl_reset, 1);
+ gpio_set_value(cardhu_dsi_pnl_reset, 0);
+ mdelay(2);
+ gpio_set_value(cardhu_dsi_pnl_reset, 1);
+ mdelay(2);
+ } else if (is_panel_219) {
+ ret = gpio_request(cardhu_dsi_219_pnl_reset, "dsi_panel_reset");
+ if (ret < 0)
+ return ret;
+ ret = gpio_direction_output(cardhu_dsi_219_pnl_reset, 0);
+ if (ret < 0) {
+ gpio_free(cardhu_dsi_219_pnl_reset);
+ return ret;
+ }
+
+ gpio_set_value(cardhu_dsi_219_pnl_reset, 0);
+ gpio_set_value(cardhu_dsi_219_pnl_reset, 1);
+ mdelay(10);
+ gpio_set_value(cardhu_dsi_219_pnl_reset, 0);
+ mdelay(10);
+ gpio_set_value(cardhu_dsi_219_pnl_reset, 1);
+ mdelay(15);
+ } else if (is_panel_1506) {
+ ret = gpio_request(cardhu_dsi_pnl_reset, "dsi_panel_reset");
+ if (ret < 0)
+ return ret;
+ ret = gpio_direction_output(cardhu_dsi_pnl_reset, 0);
+ if (ret < 0) {
+ gpio_free(cardhu_dsi_pnl_reset);
+ return ret;
+ }
+
+ gpio_set_value(cardhu_dsi_pnl_reset, 1);
+ mdelay(1);
+ gpio_set_value(cardhu_dsi_pnl_reset, 0);
+ mdelay(1);
+ gpio_set_value(cardhu_dsi_pnl_reset, 1);
+ mdelay(20);
+ }
#endif
return 0;
@@ -844,24 +864,24 @@ static int cardhu_dsi_panel_disable(void)
int err;
err = 0;
- printk(KERN_INFO "DSI panel disable\n");
-
-#if DSI_PANEL_219
- tegra_gpio_disable(cardhu_dsi_219_panel_reset);
- gpio_free(cardhu_dsi_219_panel_reset);
- tegra_gpio_disable(cardhu_bl_enb);
- gpio_free(cardhu_bl_enb);
- tegra_gpio_disable(cardhu_bl_pwm);
- gpio_free(cardhu_bl_pwm);
- tegra_gpio_disable(cardhu_lvds_shutdown);
- gpio_free(cardhu_lvds_shutdown);
-#endif
-
-#if DSI_PANEL_218
- tegra_gpio_disable(cardhu_dsi_218_panel_reset);
- gpio_free(cardhu_dsi_218_panel_reset);
-#endif
+ if (is_panel_219) {
+ gpio_free(cardhu_dsi_219_pnl_reset);
+ gpio_free(cardhu_bl_enb);
+ gpio_free(cardhu_bl_pwm);
+ gpio_free(cardhu_lvds_shutdown);
+ } else if (is_panel_218) {
+ gpio_free(cardhu_dsi_pnl_reset);
+ } else if (is_panel_1506) {
+ tegra_gpio_disable(e1506_bl_enb);
+ gpio_free(e1506_bl_enb);
+ tegra_gpio_disable(cardhu_dsi_pnl_reset);
+ gpio_free(cardhu_dsi_pnl_reset);
+ tegra_gpio_disable(e1506_panel_enb);
+ gpio_free(e1506_panel_enb);
+ tegra_gpio_disable(e1506_dsi_vddio);
+ gpio_free(e1506_dsi_vddio);
+ }
return err;
}
@@ -881,10 +901,8 @@ static int cardhu_dsi_panel_postsuspend(void)
cardhu_dsi_reg = NULL;
}
-#if DSI_PANEL_218
- tegra_gpio_disable(AVDD_LCD);
- gpio_free(AVDD_LCD);
-#endif
+ if (is_panel_218)
+ gpio_free(AVDD_LCD);
return err;
}
@@ -892,21 +910,79 @@ static int cardhu_dsi_panel_postsuspend(void)
static struct tegra_dsi_cmd dsi_init_cmd[] = {
DSI_CMD_SHORT(0x05, 0x11, 0x00),
DSI_DLY_MS(150),
+#if (DC_CTRL_MODE & TEGRA_DC_OUT_ONE_SHOT_MODE)
+ DSI_CMD_SHORT(0x15, 0x35, 0x00),
+#endif
DSI_CMD_SHORT(0x05, 0x29, 0x00),
DSI_DLY_MS(20),
};
-static struct tegra_dsi_cmd dsi_suspend_cmd[] = {
+u8 password_array[] = {0xb9, 0xff, 0x83, 0x92};
+
+static struct tegra_dsi_cmd dsi_init_cmd_1506[] = {
+ DSI_CMD_SHORT(0x05, 0x11, 0x00),
+ DSI_DLY_MS(150),
+ DSI_CMD_LONG(0x39, password_array),
+ DSI_DLY_MS(10),
+ DSI_CMD_SHORT(0x15, 0xd4, 0x0c),
+ DSI_DLY_MS(10),
+ DSI_CMD_SHORT(0x15, 0xba, 0x11),
+ DSI_DLY_MS(10),
+#if (DC_CTRL_MODE & TEGRA_DC_OUT_ONE_SHOT_MODE)
+ DSI_CMD_SHORT(0x15, 0x35, 0x00),
+#endif
+ DSI_CMD_SHORT(0x05, 0x29, 0x00),
+ DSI_DLY_MS(20),
+};
+
+static struct tegra_dsi_cmd dsi_early_suspend_cmd[] = {
DSI_CMD_SHORT(0x05, 0x28, 0x00),
DSI_DLY_MS(20),
+#if (DC_CTRL_MODE & TEGRA_DC_OUT_ONE_SHOT_MODE)
+ DSI_CMD_SHORT(0x05, 0x34, 0x00),
+#endif
+};
+
+static struct tegra_dsi_cmd dsi_late_resume_cmd[] = {
+#if (DC_CTRL_MODE & TEGRA_DC_OUT_ONE_SHOT_MODE)
+ DSI_CMD_SHORT(0x15, 0x35, 0x00),
+#endif
+ DSI_CMD_SHORT(0x05, 0x29, 0x00),
+ DSI_DLY_MS(20),
+};
+
+static struct tegra_dsi_cmd dsi_suspend_cmd[] = {
+ DSI_CMD_SHORT(0x05, 0x28, 0x00),
+ DSI_DLY_MS(120),
+#if (DC_CTRL_MODE & TEGRA_DC_OUT_ONE_SHOT_MODE)
+ DSI_CMD_SHORT(0x05, 0x34, 0x00),
+#endif
DSI_CMD_SHORT(0x05, 0x10, 0x00),
DSI_DLY_MS(5),
};
+static struct tegra_dsi_cmd dsi_suspend_cmd_1506[] = {
+ DSI_CMD_SHORT(0x05, 0x28, 0x00),
+ DSI_CMD_SHORT(0x05, 0x10, 0x00),
+ DSI_DLY_MS(120),
+};
+
struct tegra_dsi_out cardhu_dsi = {
.n_data_lanes = 2,
.pixel_format = TEGRA_DSI_PIXEL_FORMAT_24BIT_P,
+
+#if (DC_CTRL_MODE & TEGRA_DC_OUT_ONE_SHOT_MODE)
+ /*
+ * The one-shot frame time must be shorter than the time between TE.
+ * Increasing refresh_rate will result in a decrease in the frame time
+ * for one-shot. rated_refresh_rate is only an approximation of the
+ * TE rate, and is only used to report refresh rate to upper layers.
+ */
+ .refresh_rate = 66,
+ .rated_refresh_rate = 60,
+#else
.refresh_rate = 60,
+#endif
.virtual_channel = TEGRA_DSI_VIRTUAL_CHANNEL_0,
.panel_has_frame_buffer = true,
@@ -918,8 +994,11 @@ struct tegra_dsi_out cardhu_dsi = {
.panel_reset = DSI_PANEL_RESET,
.power_saving_suspend = true,
- .n_init_cmd = ARRAY_SIZE(dsi_init_cmd),
- .dsi_init_cmd = dsi_init_cmd,
+ .n_early_suspend_cmd = ARRAY_SIZE(dsi_early_suspend_cmd),
+ .dsi_early_suspend_cmd = dsi_early_suspend_cmd,
+
+ .n_late_resume_cmd = ARRAY_SIZE(dsi_late_resume_cmd),
+ .dsi_late_resume_cmd = dsi_late_resume_cmd,
.n_suspend_cmd = ARRAY_SIZE(dsi_suspend_cmd),
.dsi_suspend_cmd = dsi_suspend_cmd,
@@ -928,8 +1007,7 @@ struct tegra_dsi_out cardhu_dsi = {
.lp_cmd_mode_freq_khz = 430000,
};
-static struct tegra_dc_mode cardhu_dsi_modes[] = {
-#if DSI_PANEL_219
+static struct tegra_dc_mode cardhu_dsi_modes_219[] = {
{
.pclk = 10000000,
.h_ref_to_sync = 4,
@@ -943,9 +1021,9 @@ static struct tegra_dc_mode cardhu_dsi_modes[] = {
.h_front_porch = 32,
.v_front_porch = 2,
},
-#endif
+};
-#if DSI_PANEL_218
+static struct tegra_dc_mode cardhu_dsi_modes_218[] = {
{
.pclk = 323000000,
.h_ref_to_sync = 11,
@@ -959,28 +1037,30 @@ static struct tegra_dc_mode cardhu_dsi_modes[] = {
.h_front_porch = 16,
.v_front_porch = 4,
},
-#endif
+};
+static struct tegra_dc_mode cardhu_dsi_modes_1506[] = {
+ {
+ .pclk = 61417000,
+ .h_ref_to_sync = 2,
+ .v_ref_to_sync = 2,
+ .h_sync_width = 4,
+ .v_sync_width = 4,
+ .h_back_porch = 100,
+ .v_back_porch = 14,
+ .h_active = 720,
+ .v_active = 1280,
+ .h_front_porch = 4,
+ .v_front_porch = 4,
+ },
};
static struct tegra_fb_data cardhu_dsi_fb_data = {
-#if DSI_PANEL_219
.win = 0,
- .xres = 540,
- .yres = 960,
- .bits_per_pixel = 32,
-#endif
-
-#if DSI_PANEL_218
- .win = 0,
- .xres = 864,
- .yres = 480,
.bits_per_pixel = 32,
-#endif
.flags = TEGRA_FB_FLIP_ON_PROBE,
};
-#endif
static struct tegra_dc_out cardhu_disp1_out = {
.align = TEGRA_DC_ALIGN_MSB,
@@ -988,30 +1068,6 @@ static struct tegra_dc_out cardhu_disp1_out = {
.sd_settings = &cardhu_sd_settings,
.parent_clk = "pll_d_out0",
-#ifndef CONFIG_TEGRA_CARDHU_DSI
- .parent_clk_backup = "pll_d2_out0",
-
- .type = TEGRA_DC_OUT_RGB,
- .depth = 18,
- .dither = TEGRA_DC_ORDERED_DITHER,
-
- .modes = cardhu_panel_modes,
- .n_modes = ARRAY_SIZE(cardhu_panel_modes),
-
- .enable = cardhu_panel_enable,
- .disable = cardhu_panel_disable,
-#else
- .type = TEGRA_DC_OUT_DSI,
-
- .modes = cardhu_dsi_modes,
- .n_modes = ARRAY_SIZE(cardhu_dsi_modes),
-
- .dsi = &cardhu_dsi,
-
- .enable = cardhu_dsi_panel_enable,
- .disable = cardhu_dsi_panel_disable,
- .postsuspend = cardhu_dsi_panel_postsuspend,
-#endif
};
#ifdef CONFIG_TEGRA_DC
@@ -1019,11 +1075,6 @@ static struct tegra_dc_platform_data cardhu_disp1_pdata = {
.flags = TEGRA_DC_FLAG_ENABLED,
.default_out = &cardhu_disp1_out,
.emc_clk_rate = 300000000,
-#ifndef CONFIG_TEGRA_CARDHU_DSI
- .fb = &cardhu_fb_data,
-#else
- .fb = &cardhu_dsi_fb_data,
-#endif
};
static struct nvhost_device cardhu_disp1_device = {
@@ -1172,6 +1223,69 @@ static void cardhu_panel_late_resume(struct early_suspend *h)
}
#endif
+static void cardhu_panel_preinit(void)
+{
+ if (display_board_info.board_id == BOARD_DISPLAY_E1213)
+ is_panel_218 = true;
+ else if (display_board_info.board_id == BOARD_DISPLAY_E1253)
+ is_panel_219 = true;
+ else if (display_board_info.board_id == BOARD_DISPLAY_E1506)
+ is_panel_1506 = true;
+
+ if (!is_dsi_panel()) {
+ cardhu_disp1_out.parent_clk_backup = "pll_d2_out0";
+ cardhu_disp1_out.type = TEGRA_DC_OUT_RGB;
+ cardhu_disp1_out.depth = 18;
+ cardhu_disp1_out.dither = TEGRA_DC_ORDERED_DITHER;
+ cardhu_disp1_out.modes = cardhu_panel_modes;
+ cardhu_disp1_out.n_modes = ARRAY_SIZE(cardhu_panel_modes);
+ cardhu_disp1_out.enable = cardhu_panel_enable;
+ cardhu_disp1_out.disable = cardhu_panel_disable;
+
+ cardhu_disp1_pdata.fb = &cardhu_fb_data;
+ } else {
+ cardhu_disp1_out.flags = DC_CTRL_MODE;
+ cardhu_disp1_out.type = TEGRA_DC_OUT_DSI;
+ cardhu_disp1_out.dsi = &cardhu_dsi;
+ cardhu_disp1_out.enable = cardhu_dsi_panel_enable;
+ cardhu_disp1_out.disable = cardhu_dsi_panel_disable;
+ cardhu_disp1_out.postsuspend = cardhu_dsi_panel_postsuspend;
+
+ cardhu_dsi.n_init_cmd = ARRAY_SIZE(dsi_init_cmd);
+ cardhu_dsi.dsi_init_cmd = dsi_init_cmd;
+ cardhu_dsi.n_suspend_cmd = ARRAY_SIZE(dsi_suspend_cmd);
+ cardhu_dsi.dsi_suspend_cmd = dsi_suspend_cmd;
+
+ if (is_panel_218) {
+ cardhu_disp1_out.modes = cardhu_dsi_modes_218;
+ cardhu_disp1_out.n_modes =
+ ARRAY_SIZE(cardhu_dsi_modes_218);
+ cardhu_dsi_fb_data.xres = 864;
+ cardhu_dsi_fb_data.yres = 480;
+ } else if (is_panel_219) {
+ cardhu_disp1_out.modes = cardhu_dsi_modes_219;
+ cardhu_disp1_out.n_modes =
+ ARRAY_SIZE(cardhu_dsi_modes_219);
+ cardhu_dsi_fb_data.xres = 540;
+ cardhu_dsi_fb_data.yres = 960;
+ } else if (is_panel_1506) {
+ cardhu_disp1_out.modes = cardhu_dsi_modes_1506;
+ cardhu_disp1_out.n_modes =
+ ARRAY_SIZE(cardhu_dsi_modes_1506);
+ cardhu_dsi.n_init_cmd = ARRAY_SIZE(dsi_init_cmd_1506);
+ cardhu_dsi.dsi_init_cmd = dsi_init_cmd_1506;
+ cardhu_dsi.n_suspend_cmd =
+ ARRAY_SIZE(dsi_suspend_cmd_1506);
+ cardhu_dsi.dsi_suspend_cmd = dsi_suspend_cmd_1506;
+ cardhu_dsi.panel_send_dc_frames = true,
+ cardhu_dsi_fb_data.xres = 720;
+ cardhu_dsi_fb_data.yres = 1280;
+ }
+
+ cardhu_disp1_pdata.fb = &cardhu_dsi_fb_data;
+ }
+}
+
int __init cardhu_panel_init(void)
{
int err;
@@ -1190,7 +1304,10 @@ int __init cardhu_panel_init(void)
tegra_ion_data.heaps[0].size = tegra_carveout_size;
#endif
-#if defined(CONFIG_TEGRA_DC) && !defined(CONFIG_TEGRA_CARDHU_DSI)
+ cardhu_panel_preinit();
+ if (is_dsi_panel())
+ goto skip_lvds;
+#if defined(CONFIG_TEGRA_DC)
if (WARN_ON(board_info.board_id == BOARD_E1291 &&
((board_info.sku & SKU_TOUCHSCREEN_MECH_FIX) == 0))) {
/* use 55Hz panel timings to reduce noise on sensitive touch */
@@ -1222,28 +1339,22 @@ int __init cardhu_panel_init(void)
/* lvds configuration */
err = gpio_request(pm313_R_FDE, "R_FDE");
err |= gpio_direction_output(pm313_R_FDE, 1);
- tegra_gpio_enable(pm313_R_FDE);
err |= gpio_request(pm313_R_FB, "R_FB");
err |= gpio_direction_output(pm313_R_FB, 1);
- tegra_gpio_enable(pm313_R_FB);
err |= gpio_request(pm313_MODE0, "MODE0");
err |= gpio_direction_output(pm313_MODE0, 1);
- tegra_gpio_enable(pm313_MODE0);
err |= gpio_request(pm313_MODE1, "MODE1");
err |= gpio_direction_output(pm313_MODE1, 0);
- tegra_gpio_enable(pm313_MODE1);
err |= gpio_request(pm313_BPP, "BPP");
err |= gpio_direction_output(pm313_BPP, PM313_LVDS_PANEL_BPP);
- tegra_gpio_enable(pm313_BPP);
err = gpio_request(pm313_lvds_shutdown, "lvds_shutdown");
/* free ride provided by bootloader */
err |= gpio_direction_output(pm313_lvds_shutdown, 1);
- tegra_gpio_enable(pm313_lvds_shutdown);
if (err)
printk(KERN_ERR "ERROR(s) in LVDS configuration\n");
@@ -1254,18 +1365,22 @@ int __init cardhu_panel_init(void)
(board_info.board_id == BOARD_PM311)) {
gpio_request(e1247_pm269_lvds_shutdown, "lvds_shutdown");
gpio_direction_output(e1247_pm269_lvds_shutdown, 1);
- tegra_gpio_enable(e1247_pm269_lvds_shutdown);
} else {
gpio_request(cardhu_lvds_shutdown, "lvds_shutdown");
gpio_direction_output(cardhu_lvds_shutdown, 1);
- tegra_gpio_enable(cardhu_lvds_shutdown);
}
#endif
- tegra_gpio_enable(cardhu_hdmi_hpd);
+skip_lvds:
gpio_request(cardhu_hdmi_hpd, "hdmi_hpd");
gpio_direction_input(cardhu_hdmi_hpd);
+#if !(DC_CTRL_MODE & TEGRA_DC_OUT_ONE_SHOT_MODE)
+ tegra_gpio_enable(e1506_lcd_te);
+ gpio_request(e1506_lcd_te, "lcd_te");
+ gpio_direction_input(e1506_lcd_te);
+#endif
+
#ifdef CONFIG_HAS_EARLYSUSPEND
cardhu_panel_early_suspender.suspend = cardhu_panel_early_suspend;
cardhu_panel_early_suspender.resume = cardhu_panel_late_resume;
@@ -1274,7 +1389,7 @@ int __init cardhu_panel_init(void)
#endif
#ifdef CONFIG_TEGRA_GRHOST
- err = nvhost_device_register(&tegra_grhost_device);
+ err = tegra3_register_host1x_devices();
if (err)
return err;
#endif
diff --git a/arch/arm/mach-tegra/board-cardhu-pinmux.c b/arch/arm/mach-tegra/board-cardhu-pinmux.c
index ee2b4b48b599..7b98af0f167c 100644
--- a/arch/arm/mach-tegra/board-cardhu-pinmux.c
+++ b/arch/arm/mach-tegra/board-cardhu-pinmux.c
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/board-cardhu-pinmux.c
*
- * Copyright (C) 2011 NVIDIA Corporation
+ * Copyright (C) 2011-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
@@ -136,6 +136,17 @@ static __initdata struct tegra_drive_pingroup_config cardhu_drive_pinmux[] = {
.od = TEGRA_PIN_OD_DEFAULT, \
.ioreset = TEGRA_PIN_IO_RESET_##_ioreset \
}
+#define CEC_PINMUX(_pingroup, _mux, _pupd, _tri, _io, _lock, _od) \
+ { \
+ .pingroup = TEGRA_PINGROUP_##_pingroup, \
+ .func = TEGRA_MUX_##_mux, \
+ .pupd = TEGRA_PUPD_##_pupd, \
+ .tristate = TEGRA_TRI_##_tri, \
+ .io = TEGRA_PIN_##_io, \
+ .lock = TEGRA_PIN_LOCK_##_lock, \
+ .od = TEGRA_PIN_OD_##_od, \
+ .ioreset = TEGRA_PIN_IO_RESET_DEFAULT, \
+ }
static __initdata struct tegra_pingroup_config cardhu_pinmux_common[] = {
/* SDMMC1 pinmux */
@@ -189,6 +200,9 @@ static __initdata struct tegra_pingroup_config cardhu_pinmux_common[] = {
I2C_PINMUX(PWR_I2C_SCL, I2CPWR, NORMAL, NORMAL, INPUT, DISABLE, ENABLE),
I2C_PINMUX(PWR_I2C_SDA, I2CPWR, NORMAL, NORMAL, INPUT, DISABLE, ENABLE),
+ /* HDMI-CEC pinmux */
+ CEC_PINMUX(HDMI_CEC, CEC, NORMAL, NORMAL, INPUT, DISABLE, ENABLE),
+
DEFAULT_PINMUX(ULPI_DATA0, UARTA, NORMAL, NORMAL, OUTPUT),
DEFAULT_PINMUX(ULPI_DATA1, UARTA, NORMAL, NORMAL, INPUT),
DEFAULT_PINMUX(ULPI_DATA2, UARTA, NORMAL, NORMAL, INPUT),
@@ -495,6 +509,11 @@ static __initdata struct tegra_pingroup_config cardhu_pinmux_e1198[] = {
DEFAULT_PINMUX(SPI2_CS2_N, SPI2, PULL_UP, NORMAL, INPUT),
};
+static __initdata struct tegra_pingroup_config cardhu_pinmux_pm269_e1506[] = {
+ DEFAULT_PINMUX(LCD_M1, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_DC1, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+};
+
static __initdata struct tegra_pingroup_config unused_pins_lowpower[] = {
DEFAULT_PINMUX(GMI_WAIT, NAND, PULL_UP, TRISTATE, OUTPUT),
DEFAULT_PINMUX(GMI_ADV_N, NAND, NORMAL, TRISTATE, OUTPUT),
@@ -510,7 +529,6 @@ static __initdata struct tegra_pingroup_config unused_pins_lowpower[] = {
DEFAULT_PINMUX(GMI_AD5, NAND, NORMAL, TRISTATE, OUTPUT),
DEFAULT_PINMUX(GMI_AD6, NAND, NORMAL, TRISTATE, OUTPUT),
DEFAULT_PINMUX(GMI_AD7, NAND, NORMAL, TRISTATE, OUTPUT),
- DEFAULT_PINMUX(GMI_AD9, PWM1, NORMAL, NORMAL, OUTPUT),
DEFAULT_PINMUX(GMI_AD11, NAND, NORMAL, NORMAL, OUTPUT),
DEFAULT_PINMUX(GMI_AD13, NAND, PULL_UP, NORMAL, INPUT),
DEFAULT_PINMUX(GMI_WR_N, NAND, NORMAL, TRISTATE, OUTPUT),
@@ -528,7 +546,6 @@ static __initdata struct tegra_pingroup_config gmi_pins_269[] = {
DEFAULT_PINMUX(GMI_CS6_N, SATA, NORMAL, TRISTATE, OUTPUT),
DEFAULT_PINMUX(GMI_CS7_N, NAND, PULL_UP, NORMAL, INPUT),
DEFAULT_PINMUX(GMI_AD8, PWM0, NORMAL, NORMAL, OUTPUT),
- DEFAULT_PINMUX(GMI_AD9, PWM1, NORMAL, NORMAL, OUTPUT),
DEFAULT_PINMUX(GMI_AD10, NAND, NORMAL, NORMAL, OUTPUT),
DEFAULT_PINMUX(GMI_AD11, NAND, NORMAL, NORMAL, OUTPUT),
DEFAULT_PINMUX(GMI_AD13, NAND, PULL_UP, TRISTATE, OUTPUT),
@@ -543,11 +560,8 @@ static __initdata struct tegra_pingroup_config gmi_pins_269[] = {
static void __init cardhu_pinmux_audio_init(void)
{
- tegra_gpio_enable(TEGRA_GPIO_CDC_IRQ);
gpio_request(TEGRA_GPIO_CDC_IRQ, "wm8903");
gpio_direction_input(TEGRA_GPIO_CDC_IRQ);
-
- tegra_gpio_enable(TEGRA_GPIO_HP_DET);
}
#define GPIO_INIT_PIN_MODE(_gpio, _is_input, _value) \
@@ -622,6 +636,7 @@ static void __init cardhu_gpio_init_configure(void)
int __init cardhu_pinmux_init(void)
{
struct board_info board_info;
+ struct board_info display_board_info;
cardhu_gpio_init_configure();
@@ -630,6 +645,7 @@ int __init cardhu_pinmux_init(void)
ARRAY_SIZE(cardhu_drive_pinmux));
tegra_get_board_info(&board_info);
+ tegra_get_display_board_info(&display_board_info);
switch (board_info.board_id) {
case BOARD_E1198:
tegra_pinmux_config_table(cardhu_pinmux_e1198,
@@ -666,6 +682,12 @@ int __init cardhu_pinmux_init(void)
tegra_pinmux_config_table(cardhu_pinmux_e118x,
ARRAY_SIZE(cardhu_pinmux_e118x));
}
+
+ if (display_board_info.board_id == BOARD_DISPLAY_E1506) {
+ tegra_pinmux_config_table(cardhu_pinmux_pm269_e1506,
+ ARRAY_SIZE(cardhu_pinmux_pm269_e1506));
+ }
+
tegra_pinmux_config_table(unused_pins_lowpower,
ARRAY_SIZE(unused_pins_lowpower));
tegra_pinmux_config_table(gmi_pins_269,
@@ -702,7 +724,6 @@ struct gpio_init_pin_info pin_lpm_cardhu_common[] = {
/* E1198 without PM313 display board */
struct gpio_init_pin_info pin_lpm_cardhu_common_wo_pm313[] = {
- PIN_GPIO_LPM("GMI_AD9", TEGRA_GPIO_PH1, 0, 0),
PIN_GPIO_LPM("GMI_AD11", TEGRA_GPIO_PH3, 0, 0),
};
@@ -722,7 +743,10 @@ struct gpio_init_pin_info vddio_gmi_pins_pm269[] = {
/* PM269 without PM313 display board */
struct gpio_init_pin_info vddio_gmi_pins_pm269_wo_pm313[] = {
PIN_GPIO_LPM("GMI_CS2", TEGRA_GPIO_PK3, 1, 0),
- PIN_GPIO_LPM("GMI_AD9", TEGRA_GPIO_PH1, 0, 0),
+};
+
+struct gpio_init_pin_info vddio_gmi_pins_pm269_e1506[] = {
+ PIN_GPIO_LPM("GMI_CS2", TEGRA_GPIO_PK3, 1, 0),
};
static void set_unused_pin_gpio(struct gpio_init_pin_info *lpm_pin_info,
@@ -754,7 +778,6 @@ static void set_unused_pin_gpio(struct gpio_init_pin_info *lpm_pin_info,
gpio_free(pin_info->gpio_nr);
continue;
}
- tegra_gpio_enable(pin_info->gpio_nr);
}
}
@@ -785,7 +808,10 @@ int __init cardhu_pins_state_init(void)
set_unused_pin_gpio(&vddio_gmi_pins_pm269[0],
ARRAY_SIZE(vddio_gmi_pins_pm269));
- if (display_board_info.board_id != BOARD_DISPLAY_PM313) {
+ if (display_board_info.board_id == BOARD_DISPLAY_E1506) {
+ set_unused_pin_gpio(&vddio_gmi_pins_pm269_e1506[0],
+ ARRAY_SIZE(vddio_gmi_pins_pm269_e1506));
+ } else if (display_board_info.board_id != BOARD_DISPLAY_PM313) {
set_unused_pin_gpio(&vddio_gmi_pins_pm269_wo_pm313[0],
ARRAY_SIZE(vddio_gmi_pins_pm269_wo_pm313));
}
diff --git a/arch/arm/mach-tegra/board-cardhu-pm298-power-rails.c b/arch/arm/mach-tegra/board-cardhu-pm298-power-rails.c
index 0305ee702cbd..9168d9719b7c 100644
--- a/arch/arm/mach-tegra/board-cardhu-pm298-power-rails.c
+++ b/arch/arm/mach-tegra/board-cardhu-pm298-power-rails.c
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/board-cardhu-pm298-power-rails.c
*
- * Copyright (C) 2011 NVIDIA, Inc.
+ * 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
@@ -37,7 +37,6 @@
#include "board.h"
#include "board-cardhu.h"
#include "pm.h"
-#include "wakeups-t3.h"
#define PMC_CTRL 0x0
#define PMC_CTRL_INTR_LOW BIT(17)
@@ -676,7 +675,6 @@ static struct platform_device *fixed_reg_devs_pm269[] = {
int __init cardhu_pm298_gpio_switch_regulator_init(void)
{
- int i;
struct board_info board_info;
struct platform_device **fixed_reg_devs;
int nfixreg_devs;
@@ -698,12 +696,5 @@ int __init cardhu_pm298_gpio_switch_regulator_init(void)
break;
}
- for (i = 0; i < nfixreg_devs; ++i) {
- struct fixed_voltage_config *fixed_reg_pdata =
- fixed_reg_devs[i]->dev.platform_data;
- int gpio_nr = fixed_reg_pdata->gpio;
- if (gpio_nr < TEGRA_NR_GPIOS)
- tegra_gpio_enable(gpio_nr);
- }
return platform_add_devices(fixed_reg_devs, nfixreg_devs);
}
diff --git a/arch/arm/mach-tegra/board-cardhu-pm299-power-rails.c b/arch/arm/mach-tegra/board-cardhu-pm299-power-rails.c
index 0c55aa49acc0..32f07599fea4 100644
--- a/arch/arm/mach-tegra/board-cardhu-pm299-power-rails.c
+++ b/arch/arm/mach-tegra/board-cardhu-pm299-power-rails.c
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/board-cardhu-pm299-power-rails.c
*
- * Copyright (C) 2011 NVIDIA, Inc.
+ * 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
@@ -37,7 +37,6 @@
#include "gpio-names.h"
#include "board.h"
#include "board-cardhu.h"
-#include "wakeups-t3.h"
#define PMC_CTRL 0x0
#define PMC_CTRL_INTR_LOW (1 << 17)
@@ -666,7 +665,6 @@ static struct platform_device *fixed_reg_devs_pm269[] = {
int __init cardhu_pm299_gpio_switch_regulator_init(void)
{
- int i;
struct board_info board_info;
struct platform_device **fixed_reg_devs;
int nfixreg_devs;
@@ -688,12 +686,5 @@ int __init cardhu_pm299_gpio_switch_regulator_init(void)
break;
}
- for (i = 0; i < nfixreg_devs; ++i) {
- struct fixed_voltage_config *fixed_reg_pdata =
- fixed_reg_devs[i]->dev.platform_data;
- int gpio_nr = fixed_reg_pdata->gpio;
- if (gpio_nr < TEGRA_NR_GPIOS)
- tegra_gpio_enable(gpio_nr);
- }
return platform_add_devices(fixed_reg_devs, nfixreg_devs);
}
diff --git a/arch/arm/mach-tegra/board-cardhu-power.c b/arch/arm/mach-tegra/board-cardhu-power.c
index 1bc811ef9611..ace103f5ba6b 100644
--- a/arch/arm/mach-tegra/board-cardhu-power.c
+++ b/arch/arm/mach-tegra/board-cardhu-power.c
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/board-cardhu-power.c
*
- * Copyright (C) 2011 NVIDIA, Inc.
+ * 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
@@ -42,8 +42,9 @@
#include "board.h"
#include "board-cardhu.h"
#include "pm.h"
-#include "wakeups-t3.h"
#include "tegra3_tsensor.h"
+#include "wakeups.h"
+#include "wakeups-t3.h"
#define PMC_CTRL 0x0
#define PMC_CTRL_INTR_LOW (1 << 17)
@@ -486,7 +487,8 @@ int __init cardhu_regulator_init(void)
/* E1291-A04/A05: Enable DEV_SLP and enable sleep on GPIO2 */
if ((board_info.board_id == BOARD_E1291) &&
((board_info.fab == BOARD_FAB_A04) ||
- (board_info.fab == BOARD_FAB_A05))) {
+ (board_info.fab == BOARD_FAB_A05) ||
+ (board_info.fab == BOARD_FAB_A07))) {
tps_platform.dev_slp_en = true;
tps_platform.gpio_init_data = tps_gpio_pdata_e1291_a04;
tps_platform.num_gpioinit_data =
@@ -603,12 +605,14 @@ static struct regulator_consumer_supply fixed_reg_en_vdd_pnl1_supply[] = {
static struct regulator_consumer_supply fixed_reg_cam1_ldo_en_supply[] = {
REGULATOR_SUPPLY("vdd_2v8_cam1", NULL),
REGULATOR_SUPPLY("avdd", "6-0072"),
+ REGULATOR_SUPPLY("vdd", "6-000e"),
};
/* CAM2_LDO_EN from AP GPIO KB_ROW7 R07*/
static struct regulator_consumer_supply fixed_reg_cam2_ldo_en_supply[] = {
REGULATOR_SUPPLY("vdd_2v8_cam2", NULL),
REGULATOR_SUPPLY("avdd", "7-0072"),
+ REGULATOR_SUPPLY("vdd", "7-000e"),
};
/* CAM3_LDO_EN from AP GPIO KB_ROW8 S00*/
@@ -648,6 +652,8 @@ static struct regulator_consumer_supply fixed_reg_en_1v8_cam_supply[] = {
REGULATOR_SUPPLY("vdd_1v8_cam3", NULL),
REGULATOR_SUPPLY("dvdd", "6-0072"),
REGULATOR_SUPPLY("dvdd", "7-0072"),
+ REGULATOR_SUPPLY("vdd_i2c", "6-000e"),
+ REGULATOR_SUPPLY("vdd_i2c", "7-000e"),
REGULATOR_SUPPLY("vdd_i2c", "2-0033"),
};
@@ -741,9 +747,7 @@ FIXED_REG(3, en_3v3_sys_a04, en_3v3_sys, NULL, 0, 0, TPS6591X_GPIO_
/* Specific to pm269 */
FIXED_REG(4, en_vdd_bl_pm269, en_vdd_bl, NULL, 0, 0, TEGRA_GPIO_PH3, true, 1, 5000);
-#ifndef CONFIG_TEGRA_CARDHU_DSI
FIXED_REG(6, en_vdd_pnl1_pm269, en_vdd_pnl1, FIXED_SUPPLY(en_3v3_sys), 0, 0, TEGRA_GPIO_PW1, true, 1, 3300);
-#endif
FIXED_REG(9, en_3v3_fuse_pm269, en_3v3_fuse, FIXED_SUPPLY(en_3v3_sys), 0, 0, TEGRA_GPIO_PC1, true, 0, 3300);
FIXED_REG(12, en_3v3_pex_hvdd_pm269, en_3v3_pex_hvdd, FIXED_SUPPLY(en_3v3_sys), 0, 0, TEGRA_GPIO_PC6, true, 0, 3300);
@@ -837,6 +841,7 @@ FIXED_REG_OD(17, en_vddio_vid_oc, en_vddio_vid_oc, FIXED_SUPPLY(en_5v0), 0,
ADD_FIXED_REG(en_3v3_pex_hvdd_pm269), \
ADD_FIXED_REG(en_1v8_cam), \
ADD_FIXED_REG(dis_5v_switch_e118x), \
+ ADD_FIXED_REG(en_vbrtr), \
ADD_FIXED_REG(en_usb1_vbus_oc_e118x), \
ADD_FIXED_REG(en_usb3_vbus_oc_e118x), \
ADD_FIXED_REG(en_vddio_vid_oc_pm269),
@@ -861,14 +866,12 @@ FIXED_REG_OD(17, en_vddio_vid_oc, en_vddio_vid_oc, FIXED_SUPPLY(en_5v0), 0,
ADD_FIXED_REG(en_vddio_vid_oc_pm269),
-#ifndef CONFIG_TEGRA_CARDHU_DSI
#define E1247_DISPLAY_FIXED_REG \
ADD_FIXED_REG(en_vdd_bl_pm269), \
ADD_FIXED_REG(en_vdd_pnl1_pm269),
-#else
-#define E1247_DISPLAY_FIXED_REG \
+
+#define E1247_DSI_DISPLAY_FIXED_REG \
ADD_FIXED_REG(en_vdd_bl_pm269),
-#endif
#define PM313_DISPLAY_FIXED_REG \
ADD_FIXED_REG(en_vdd_bl_pm313), \
@@ -915,6 +918,11 @@ static struct platform_device *fixed_reg_devs_e118x[] = {
E1247_DISPLAY_FIXED_REG
};
+static struct platform_device *fixed_reg_devs_e118x_dsi[] = {
+ E118x_FIXED_REG
+ E1247_DSI_DISPLAY_FIXED_REG
+};
+
/* Fixed regulator devices for E1186/E1187/E1256 */
static struct platform_device *fixed_reg_devs_e118x_pm313[] = {
E118x_FIXED_REG
@@ -957,6 +965,11 @@ static struct platform_device *fixed_reg_devs_pm269[] = {
E1247_DISPLAY_FIXED_REG
};
+static struct platform_device *fixed_reg_devs_pm269_dsi[] = {
+ PM269_FIXED_REG
+ E1247_DSI_DISPLAY_FIXED_REG
+};
+
/* Fixed regulator devices for PM269 */
static struct platform_device *fixed_reg_devs_pm269_pm313[] = {
PM269_FIXED_REG
@@ -969,6 +982,11 @@ static struct platform_device *fixed_reg_devs_pm311[] = {
E1247_DISPLAY_FIXED_REG
};
+static struct platform_device *fixed_reg_devs_pm311_dsi[] = {
+ PM311_FIXED_REG
+ E1247_DSI_DISPLAY_FIXED_REG
+};
+
/* Fixed regulator devices for PM11 */
static struct platform_device *fixed_reg_devs_pm311_pm313[] = {
PM311_FIXED_REG
@@ -989,9 +1007,15 @@ static struct platform_device *fixed_reg_devs_e1291_a04[] = {
E1198_FIXED_REG
};
+static bool is_display_board_dsi(u16 display_board_id)
+{
+ return ((display_board_id == BOARD_DISPLAY_E1213) ||
+ (display_board_id == BOARD_DISPLAY_E1253) ||
+ (display_board_id == BOARD_DISPLAY_E1506));
+}
+
int __init cardhu_fixed_regulator_init(void)
{
- int i;
struct board_info board_info;
struct board_info pmu_board_info;
struct board_info display_board_info;
@@ -1027,7 +1051,8 @@ int __init cardhu_fixed_regulator_init(void)
nfixreg_devs = ARRAY_SIZE(fixed_reg_devs_e1291_a03);
fixed_reg_devs = fixed_reg_devs_e1291_a03;
} else if ((board_info.fab == BOARD_FAB_A04) ||
- (board_info.fab == BOARD_FAB_A05)) {
+ (board_info.fab == BOARD_FAB_A05) ||
+ (board_info.fab == BOARD_FAB_A07)) {
nfixreg_devs = ARRAY_SIZE(fixed_reg_devs_e1291_a04);
fixed_reg_devs = fixed_reg_devs_e1291_a04;
} else {
@@ -1043,6 +1068,9 @@ int __init cardhu_fixed_regulator_init(void)
if (display_board_info.board_id == BOARD_DISPLAY_PM313) {
nfixreg_devs = ARRAY_SIZE(fixed_reg_devs_pm311_pm313);
fixed_reg_devs = fixed_reg_devs_pm311_pm313;
+ } else if (is_display_board_dsi(display_board_info.board_id)) {
+ nfixreg_devs = ARRAY_SIZE(fixed_reg_devs_pm311_dsi);
+ fixed_reg_devs = fixed_reg_devs_pm311_dsi;
}
break;
@@ -1053,6 +1081,9 @@ int __init cardhu_fixed_regulator_init(void)
if (display_board_info.board_id == BOARD_DISPLAY_PM313) {
nfixreg_devs = ARRAY_SIZE(fixed_reg_devs_pm269_pm313);
fixed_reg_devs = fixed_reg_devs_pm269_pm313;
+ } else if (is_display_board_dsi(display_board_info.board_id)) {
+ nfixreg_devs = ARRAY_SIZE(fixed_reg_devs_pm269_dsi);
+ fixed_reg_devs = fixed_reg_devs_pm269_dsi;
} else {
nfixreg_devs = ARRAY_SIZE(fixed_reg_devs_pm269);
fixed_reg_devs = fixed_reg_devs_pm269;
@@ -1063,6 +1094,9 @@ int __init cardhu_fixed_regulator_init(void)
if (display_board_info.board_id == BOARD_DISPLAY_PM313) {
nfixreg_devs = ARRAY_SIZE(fixed_reg_devs_e118x_pm313);
fixed_reg_devs = fixed_reg_devs_e118x_pm313;
+ } else if (is_display_board_dsi(display_board_info.board_id)) {
+ nfixreg_devs = ARRAY_SIZE(fixed_reg_devs_e118x_dsi);
+ fixed_reg_devs = fixed_reg_devs_e118x_dsi;
} else {
nfixreg_devs = ARRAY_SIZE(fixed_reg_devs_e118x);
fixed_reg_devs = fixed_reg_devs_e118x;
@@ -1070,13 +1104,6 @@ int __init cardhu_fixed_regulator_init(void)
break;
}
- for (i = 0; i < nfixreg_devs; ++i) {
- struct fixed_voltage_config *fixed_reg_pdata =
- fixed_reg_devs[i]->dev.platform_data;
- int gpio_nr = fixed_reg_pdata->gpio;
- if (gpio_nr < TEGRA_NR_GPIOS)
- tegra_gpio_enable(gpio_nr);
- }
return platform_add_devices(fixed_reg_devs, nfixreg_devs);
}
subsys_initcall_sync(cardhu_fixed_regulator_init);
@@ -1130,8 +1157,15 @@ int __init cardhu_suspend_init(void)
/* CORE_PWR_REQ to be high for E1291-A03 */
if (board_info.fab == BOARD_FAB_A03)
cardhu_suspend_data.corereq_high = true;
+ if (board_info.fab < BOARD_FAB_A03)
+ /* post E1291-A02 revisions WAKE19/USB1-VBUS wake supported */
+ tegra_disable_wake_source(TEGRA_WAKE_USB1_VBUS);
break;
case BOARD_E1198:
+ if (board_info.fab < BOARD_FAB_A02)
+ /* post E1198-A01 revisions WAKE19/USB1-VBUS wake supported */
+ tegra_disable_wake_source(TEGRA_WAKE_USB1_VBUS);
+ break;
case BOARD_PM269:
case BOARD_PM305:
case BOARD_PM311:
diff --git a/arch/arm/mach-tegra/board-cardhu-sdhci.c b/arch/arm/mach-tegra/board-cardhu-sdhci.c
index 73bd1f2c308a..d8be9fe6747f 100644
--- a/arch/arm/mach-tegra/board-cardhu-sdhci.c
+++ b/arch/arm/mach-tegra/board-cardhu-sdhci.c
@@ -2,7 +2,7 @@
* arch/arm/mach-tegra/board-harmony-sdhci.c
*
* Copyright (C) 2010 Google, Inc.
- * Copyright (C) 2011 NVIDIA Corporation.
+ * Copyright (C) 2011-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
@@ -145,6 +145,7 @@ static struct tegra_sdhci_platform_data tegra_sdhci_platform_data2 = {
.embedded_sdio = &embedded_sdio_data2,
#endif
.built_in = 0,
+ .ocr_mask = MMC_OCR_1V8_MASK,
},
#ifndef CONFIG_MMC_EMBEDDED_SDIO
.pm_flags = MMC_PM_KEEP_POWER,
@@ -152,8 +153,9 @@ static struct tegra_sdhci_platform_data tegra_sdhci_platform_data2 = {
.cd_gpio = -1,
.wp_gpio = -1,
.power_gpio = -1,
-/* .tap_delay = 6,
- .is_voltage_switch_supported = false,
+ .tap_delay = 0x0F,
+ .ddr_clk_limit = 41000000,
+/* .is_voltage_switch_supported = false,
.vdd_rail_name = NULL,
.slot_rail_name = NULL,
.vdd_max_uv = -1,
@@ -166,8 +168,9 @@ static struct tegra_sdhci_platform_data tegra_sdhci_platform_data0 = {
.cd_gpio = CARDHU_SD_CD,
.wp_gpio = CARDHU_SD_WP,
.power_gpio = -1,
-/* .tap_delay = 6,
- .is_voltage_switch_supported = true,
+ .tap_delay = 0x0F,
+ .ddr_clk_limit = 41000000,
+/* .is_voltage_switch_supported = true,
.vdd_rail_name = "vddio_sdmmc1",
.slot_rail_name = "vddio_sd_slot",
.vdd_max_uv = 3320000,
@@ -182,11 +185,11 @@ static struct tegra_sdhci_platform_data tegra_sdhci_platform_data3 = {
.power_gpio = -1,
.is_8bit = 1,
.tap_delay = 0x0F,
+ .ddr_clk_limit = 41000000,
.mmc_data = {
.built_in = 1,
}
-/* .tap_delay = 6,
- .is_voltage_switch_supported = false,
+/* .is_voltage_switch_supported = false,
.vdd_rail_name = NULL,
.slot_rail_name = NULL,
.vdd_max_uv = -1,
@@ -278,10 +281,6 @@ static int __init cardhu_wifi_init(void)
if (rc)
pr_err("WLAN_WOW gpio request failed:%d\n", rc);
- tegra_gpio_enable(CARDHU_WLAN_PWR);
- tegra_gpio_enable(CARDHU_WLAN_RST);
- tegra_gpio_enable(CARDHU_WLAN_WOW);
-
rc = gpio_direction_output(CARDHU_WLAN_PWR, 0);
if (rc)
pr_err("WLAN_PWR gpio direction configuration failed:%d\n", rc);
diff --git a/arch/arm/mach-tegra/board-cardhu-sensors.c b/arch/arm/mach-tegra/board-cardhu-sensors.c
index fe3188ec1cfd..bb6a2ae5774d 100644
--- a/arch/arm/mach-tegra/board-cardhu-sensors.c
+++ b/arch/arm/mach-tegra/board-cardhu-sensors.c
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/board-cardhu-sensors.c
*
- * Copyright (c) 2010-2011, NVIDIA CORPORATION, All rights reserved.
+ * Copyright (c) 2010-2012, NVIDIA CORPORATION, All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -40,6 +40,7 @@
#include <mach/fb.h>
#include <mach/gpio.h>
#include <media/ov5650.h>
+#include <media/ov5640.h>
#include <media/ov14810.h>
#include <media/ov2710.h>
#include <media/tps61050.h>
@@ -48,10 +49,12 @@
#include "board.h"
#include <linux/mpu.h>
#include <media/sh532u.h>
+#include <media/ad5816.h>
#include <linux/bq27x00.h>
#include <mach/gpio.h>
#include <mach/edp.h>
#include <mach/thermal.h>
+#include <linux/therm_est.h>
#include "gpio-names.h"
#include "board-cardhu.h"
@@ -86,24 +89,20 @@ static int cardhu_camera_init(void)
* and donot have TCA6416 exp for camera */
if ((board_info.board_id == BOARD_E1198) ||
(board_info.board_id == BOARD_E1291)) {
- tegra_gpio_enable(CAM1_POWER_DWN_GPIO);
ret = gpio_request(CAM1_POWER_DWN_GPIO, "camera_power_en");
if (ret < 0)
pr_err("%s: gpio_request failed for gpio %s\n",
__func__, "CAM1_POWER_DWN_GPIO");
- tegra_gpio_enable(CAM3_POWER_DWN_GPIO);
ret = gpio_request(CAM3_POWER_DWN_GPIO, "cam3_power_en");
if (ret < 0)
pr_err("%s: gpio_request failed for gpio %s\n",
__func__, "CAM3_POWER_DWN_GPIO");
- tegra_gpio_enable(CAM2_POWER_DWN_GPIO);
ret = gpio_request(CAM2_POWER_DWN_GPIO, "camera2_power_en");
if (ret < 0)
pr_err("%s: gpio_request failed for gpio %s\n",
__func__, "CAM2_POWER_DWN_GPIO");
- tegra_gpio_enable(OV5650_RESETN_GPIO);
ret = gpio_request(OV5650_RESETN_GPIO, "camera_reset");
if (ret < 0)
pr_err("%s: gpio_request failed for gpio %s\n",
@@ -123,7 +122,6 @@ static int cardhu_camera_init(void)
}
/* To select the CSIB MUX either for cam2 or cam3 */
- tegra_gpio_enable(CAMERA_CSI_MUX_SEL_GPIO);
ret = gpio_request(CAMERA_CSI_MUX_SEL_GPIO, "camera_csi_sel");
if (ret < 0)
pr_err("%s: gpio_request failed for gpio %s\n",
@@ -464,6 +462,86 @@ struct ov2710_platform_data cardhu_ov2710_data = {
.power_off = cardhu_ov2710_power_off,
};
+static int cardhu_ov5640_power_on(void)
+{
+ /* CSI-B and front sensor are muxed on cardhu */
+ gpio_direction_output(CAMERA_CSI_MUX_SEL_GPIO, 1);
+
+ /* Boards E1198 and E1291 are of Cardhu personality
+ * and donot have TCA6416 exp for camera */
+ if ((board_info.board_id == BOARD_E1198) ||
+ (board_info.board_id == BOARD_E1291)) {
+
+ gpio_direction_output(CAM1_POWER_DWN_GPIO, 0);
+ gpio_direction_output(CAM2_POWER_DWN_GPIO, 0);
+ gpio_direction_output(CAM3_POWER_DWN_GPIO, 0);
+ mdelay(10);
+
+ if (cardhu_vdd_cam3 == NULL) {
+ cardhu_vdd_cam3 = regulator_get(NULL, "vdd_cam3");
+ if (WARN_ON(IS_ERR(cardhu_vdd_cam3))) {
+ pr_err("%s: couldn't get regulator vdd_cam3: %ld\n",
+ __func__, PTR_ERR(cardhu_vdd_cam3));
+ goto reg_alloc_fail;
+ }
+ }
+ regulator_enable(cardhu_vdd_cam3);
+ }
+
+ /* Enable VDD_1V8_Cam3 */
+ if (cardhu_1v8_cam3 == NULL) {
+ cardhu_1v8_cam3 = regulator_get(NULL, "vdd_1v8_cam3");
+ if (WARN_ON(IS_ERR(cardhu_1v8_cam3))) {
+ pr_err("%s: couldn't get regulator vdd_1v8_cam3: %ld\n",
+ __func__, PTR_ERR(cardhu_1v8_cam3));
+ goto reg_alloc_fail;
+ }
+ }
+ regulator_enable(cardhu_1v8_cam3);
+ mdelay(5);
+
+ return 0;
+
+reg_alloc_fail:
+ if (cardhu_1v8_cam3) {
+ regulator_put(cardhu_1v8_cam3);
+ cardhu_1v8_cam3 = NULL;
+ }
+ if (cardhu_vdd_cam3) {
+ regulator_put(cardhu_vdd_cam3);
+ cardhu_vdd_cam3 = NULL;
+ }
+
+ return -ENODEV;
+}
+
+static int cardhu_ov5640_power_off(void)
+{
+ /* CSI-B and front sensor are muxed on cardhu */
+ gpio_direction_output(CAMERA_CSI_MUX_SEL_GPIO, 1);
+
+ /* Boards E1198 and E1291 are of Cardhu personality
+ * and donot have TCA6416 exp for camera */
+ if ((board_info.board_id == BOARD_E1198) ||
+ (board_info.board_id == BOARD_E1291)) {
+ gpio_direction_output(CAM1_POWER_DWN_GPIO, 1);
+ gpio_direction_output(CAM2_POWER_DWN_GPIO, 1);
+ gpio_direction_output(CAM3_POWER_DWN_GPIO, 1);
+ }
+
+ if (cardhu_1v8_cam3)
+ regulator_disable(cardhu_1v8_cam3);
+ if (cardhu_vdd_cam3)
+ regulator_disable(cardhu_vdd_cam3);
+
+ return 0;
+}
+
+struct ov5640_platform_data cardhu_ov5640_data = {
+ .power_on = cardhu_ov5640_power_on,
+ .power_off = cardhu_ov5640_power_off,
+};
+
static const struct i2c_board_info cardhu_i2c3_board_info[] = {
{
I2C_BOARD_INFO("pca9546", 0x70),
@@ -499,7 +577,7 @@ static struct nvc_gpio_pdata pm269_sh532u_left_gpio_pdata[] = {
};
static struct sh532u_platform_data pm269_sh532u_left_pdata = {
- .cfg = NVC_CFG_NODEV,
+ .cfg = 0,
.num = 1,
.sync = 2,
.dev_name = "focuser",
@@ -512,7 +590,7 @@ static struct nvc_gpio_pdata pm269_sh532u_right_gpio_pdata[] = {
};
static struct sh532u_platform_data pm269_sh532u_right_pdata = {
- .cfg = NVC_CFG_NODEV,
+ .cfg = 0,
.num = 2,
.sync = 1,
.dev_name = "focuser",
@@ -520,6 +598,54 @@ static struct sh532u_platform_data pm269_sh532u_right_pdata = {
.gpio = pm269_sh532u_right_gpio_pdata,
};
+static struct nvc_gpio_pdata ad5816_gpio_pdata[] = {
+ { AD5816_GPIO_RESET, TEGRA_GPIO_PBB0, false, 0, },
+};
+
+static struct ad5816_platform_data ad5816_left_pdata = {
+ .cfg = 0,
+ .num = 1,
+ .sync = 2,
+ .dev_name = "focuser",
+ .gpio_count = ARRAY_SIZE(ad5816_gpio_pdata),
+ .gpio = ad5816_gpio_pdata,
+};
+
+static struct ad5816_platform_data ad5816_right_pdata = {
+ .cfg = 0,
+ .num = 2,
+ .sync = 1,
+ .dev_name = "focuser",
+ .gpio_count = ARRAY_SIZE(ad5816_gpio_pdata),
+ .gpio = ad5816_gpio_pdata,
+};
+
+static struct nvc_gpio_pdata pm269_ad5816_left_gpio_pdata[] = {
+ { AD5816_GPIO_RESET, CAM1_RST_L_GPIO, false, 0, },
+};
+
+static struct ad5816_platform_data pm269_ad5816_left_pdata = {
+ .cfg = NVC_CFG_NODEV,
+ .num = 1,
+ .sync = 2,
+ .dev_name = "focuser",
+ .gpio_count = ARRAY_SIZE(pm269_ad5816_left_gpio_pdata),
+ .gpio = pm269_ad5816_left_gpio_pdata,
+};
+
+static struct nvc_gpio_pdata pm269_ad5816_right_gpio_pdata[] = {
+ { AD5816_GPIO_RESET, CAM2_RST_L_GPIO, false, 0, },
+};
+
+static struct ad5816_platform_data pm269_ad5816_right_pdata = {
+ .cfg = NVC_CFG_NODEV,
+ .num = 2,
+ .sync = 1,
+ .dev_name = "focuser",
+ .gpio_count = ARRAY_SIZE(pm269_ad5816_right_gpio_pdata),
+ .gpio = pm269_ad5816_right_gpio_pdata,
+};
+
static struct nvc_torch_pin_state cardhu_tps61050_pinstate = {
.mask = 0x0008, /*VGP3*/
@@ -547,6 +673,10 @@ static struct i2c_board_info cardhu_i2c6_board_info[] = {
I2C_BOARD_INFO("sh532u", 0x72),
.platform_data = &sh532u_left_pdata,
},
+ {
+ I2C_BOARD_INFO("ad5816", 0x0E),
+ .platform_data = &ad5816_left_pdata,
+ },
};
static struct i2c_board_info cardhu_i2c7_board_info[] = {
@@ -558,6 +688,10 @@ static struct i2c_board_info cardhu_i2c7_board_info[] = {
I2C_BOARD_INFO("sh532u", 0x72),
.platform_data = &sh532u_right_pdata,
},
+ {
+ I2C_BOARD_INFO("ad5816", 0x0E),
+ .platform_data = &ad5816_right_pdata,
+ },
};
static struct i2c_board_info pm269_i2c6_board_info[] = {
@@ -569,6 +703,10 @@ static struct i2c_board_info pm269_i2c6_board_info[] = {
I2C_BOARD_INFO("sh532u", 0x72),
.platform_data = &pm269_sh532u_left_pdata,
},
+ {
+ I2C_BOARD_INFO("ad5816", 0x0E),
+ .platform_data = &pm269_ad5816_left_pdata,
+ },
};
static struct i2c_board_info pm269_i2c7_board_info[] = {
@@ -580,6 +718,10 @@ static struct i2c_board_info pm269_i2c7_board_info[] = {
I2C_BOARD_INFO("sh532u", 0x72),
.platform_data = &pm269_sh532u_right_pdata,
},
+ {
+ I2C_BOARD_INFO("ad5816", 0x0E),
+ .platform_data = &pm269_ad5816_right_pdata,
+ },
};
static struct i2c_board_info cardhu_i2c8_board_info[] = {
@@ -587,6 +729,10 @@ static struct i2c_board_info cardhu_i2c8_board_info[] = {
I2C_BOARD_INFO("ov2710", 0x36),
.platform_data = &cardhu_ov2710_data,
},
+ {
+ I2C_BOARD_INFO("ov5640", 0x3C),
+ .platform_data = &cardhu_ov5640_data,
+ },
};
static int nct_get_temp(void *_data, long *temp)
@@ -625,27 +771,56 @@ static int nct_set_shutdown_temp(void *_data, long shutdown_temp)
return nct1008_thermal_set_shutdown_temp(data, shutdown_temp);
}
+#ifdef CONFIG_TEGRA_SKIN_THROTTLE
+static int nct_get_itemp(void *dev_data, long *temp)
+{
+ struct nct1008_data *data = dev_data;
+ return nct1008_thermal_get_temps(data, NULL, temp);
+}
+#endif
+
static void nct1008_probe_callback(struct nct1008_data *data)
{
- struct tegra_thermal_device *thermal_device;
+ struct tegra_thermal_device *ext_nct;
- thermal_device = kzalloc(sizeof(struct tegra_thermal_device),
+ ext_nct = kzalloc(sizeof(struct tegra_thermal_device),
GFP_KERNEL);
- if (!thermal_device) {
+ if (!ext_nct) {
pr_err("unable to allocate thermal device\n");
return;
}
- thermal_device->name = "nct1008";
- thermal_device->data = data;
- thermal_device->offset = TDIODE_OFFSET;
- thermal_device->get_temp = nct_get_temp;
- thermal_device->get_temp_low = nct_get_temp_low;
- thermal_device->set_limits = nct_set_limits;
- thermal_device->set_alert = nct_set_alert;
- thermal_device->set_shutdown_temp = nct_set_shutdown_temp;
+ ext_nct->name = "nct_ext";
+ ext_nct->id = THERMAL_DEVICE_ID_NCT_EXT;
+ ext_nct->data = data;
+ ext_nct->offset = TDIODE_OFFSET;
+ ext_nct->get_temp = nct_get_temp;
+ ext_nct->get_temp_low = nct_get_temp_low;
+ ext_nct->set_limits = nct_set_limits;
+ ext_nct->set_alert = nct_set_alert;
+ ext_nct->set_shutdown_temp = nct_set_shutdown_temp;
- tegra_thermal_set_device(thermal_device);
+ tegra_thermal_device_register(ext_nct);
+
+#ifdef CONFIG_TEGRA_SKIN_THROTTLE
+ {
+ struct tegra_thermal_device *int_nct;
+ int_nct = kzalloc(sizeof(struct tegra_thermal_device),
+ GFP_KERNEL);
+ if (!int_nct) {
+ kfree(int_nct);
+ pr_err("unable to allocate thermal device\n");
+ return;
+ }
+
+ int_nct->name = "nct_int";
+ int_nct->id = THERMAL_DEVICE_ID_NCT_INT;
+ int_nct->data = data;
+ int_nct->get_temp = nct_get_itemp;
+
+ tegra_thermal_device_register(int_nct);
+ }
+#endif
}
static struct nct1008_platform_data cardhu_nct1008_pdata = {
@@ -700,8 +875,6 @@ static int cardhu_nct1008_init(void)
ret = gpio_direction_input(nct1008_port);
if (ret < 0)
gpio_free(nct1008_port);
- else
- tegra_gpio_enable(nct1008_port);
}
return ret;
@@ -831,7 +1004,6 @@ static void mpuirq_init(void)
#if (MPU_GYRO_TYPE == MPU_TYPE_MPU3050)
#if MPU_ACCEL_IRQ_GPIO
/* ACCEL-IRQ assignment */
- tegra_gpio_enable(MPU_ACCEL_IRQ_GPIO);
ret = gpio_request(MPU_ACCEL_IRQ_GPIO, MPU_ACCEL_NAME);
if (ret < 0) {
pr_err("%s: gpio_request failed %d\n", __func__, ret);
@@ -848,7 +1020,6 @@ static void mpuirq_init(void)
#endif
/* MPU-IRQ assignment */
- tegra_gpio_enable(MPU_GYRO_IRQ_GPIO);
ret = gpio_request(MPU_GYRO_IRQ_GPIO, MPU_GYRO_NAME);
if (ret < 0) {
pr_err("%s: gpio_request failed %d\n", __func__, ret);
diff --git a/arch/arm/mach-tegra/board-cardhu.c b/arch/arm/mach-tegra/board-cardhu.c
index cce0d4df6885..b5fa3f316698 100644
--- a/arch/arm/mach-tegra/board-cardhu.c
+++ b/arch/arm/mach-tegra/board-cardhu.c
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/board-cardhu.c
*
- * Copyright (c) 2011-2012, 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
@@ -39,6 +39,7 @@
#include <linux/memblock.h>
#include <linux/spi-tegra.h>
#include <linux/nfc/pn544.h>
+#include <linux/rfkill-gpio.h>
#include <sound/wm8903.h>
#include <sound/max98095.h>
@@ -58,6 +59,7 @@
#include <mach/usb_phy.h>
#include <mach/thermal.h>
#include <mach/pci.h>
+#include <mach/tegra_fiq_debugger.h>
#include "board.h"
#include "clock.h"
@@ -70,75 +72,109 @@
#include "baseband-xmm-power.h"
#include "wdt-recovery.h"
+static struct balanced_throttle throttle_list[] = {
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
+ {
+ .id = BALANCED_THROTTLE_ID_TJ,
+ .throt_tab_size = 10,
+ .throt_tab = {
+ { 0, 1000 },
+ { 640000, 1000 },
+ { 640000, 1000 },
+ { 640000, 1000 },
+ { 640000, 1000 },
+ { 640000, 1000 },
+ { 760000, 1000 },
+ { 760000, 1050 },
+ {1000000, 1050 },
+ {1000000, 1100 },
+ },
+ },
+#endif
+#ifdef CONFIG_TEGRA_SKIN_THROTTLE
+ {
+ .id = BALANCED_THROTTLE_ID_SKIN,
+ .throt_tab_size = 6,
+ .throt_tab = {
+ { 640000, 1200 },
+ { 640000, 1200 },
+ { 760000, 1200 },
+ { 760000, 1200 },
+ {1000000, 1200 },
+ {1000000, 1200 },
+ },
+ },
+#endif
+};
+
/* All units are in millicelsius */
static struct tegra_thermal_data thermal_data = {
- .temp_throttle = 85000,
+ .shutdown_device_id = THERMAL_DEVICE_ID_NCT_EXT,
.temp_shutdown = 90000,
- .temp_offset = TDIODE_OFFSET, /* temps based on tdiode */
+
+#if defined(CONFIG_TEGRA_EDP_LIMITS) || defined(CONFIG_TEGRA_THERMAL_THROTTLE)
+ .throttle_edp_device_id = THERMAL_DEVICE_ID_NCT_EXT,
+#endif
#ifdef CONFIG_TEGRA_EDP_LIMITS
.edp_offset = TDIODE_OFFSET, /* edp based on tdiode */
.hysteresis_edp = 3000,
#endif
-#ifdef CONFIG_TEGRA_THERMAL_SYSFS
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
+ .temp_throttle = 85000,
.tc1 = 0,
.tc2 = 1,
.passive_delay = 2000,
-#else
- .hysteresis_throttle = 1000,
#endif
-};
-
-/* !!!TODO: Change for cardhu (Taken from Ventana) */
-static struct tegra_utmip_config utmi_phy_config[] = {
- [0] = {
- .hssync_start_delay = 0,
- .idle_wait_delay = 17,
- .elastic_limit = 16,
- .term_range_adj = 6,
- .xcvr_setup = 15,
- .xcvr_setup_offset = 0,
- .xcvr_use_fuses = 1,
- .xcvr_lsfslew = 2,
- .xcvr_lsrslew = 2,
- },
- [1] = {
- .hssync_start_delay = 0,
- .idle_wait_delay = 17,
- .elastic_limit = 16,
- .term_range_adj = 6,
- .xcvr_setup = 15,
- .xcvr_setup_offset = 0,
- .xcvr_use_fuses = 1,
- .xcvr_lsfslew = 2,
- .xcvr_lsrslew = 2,
- },
- [2] = {
- .hssync_start_delay = 0,
- .idle_wait_delay = 17,
- .elastic_limit = 16,
- .term_range_adj = 6,
- .xcvr_setup = 8,
- .xcvr_setup_offset = 0,
- .xcvr_use_fuses = 1,
- .xcvr_lsfslew = 2,
- .xcvr_lsrslew = 2,
+#ifdef CONFIG_TEGRA_SKIN_THROTTLE
+ .skin_device_id = THERMAL_DEVICE_ID_SKIN,
+ .temp_throttle_skin = 43000,
+ .tc1_skin = 0,
+ .tc2_skin = 1,
+ .passive_delay_skin = 5000,
+
+ .skin_temp_offset = 9793,
+ .skin_period = 1100,
+ .skin_devs_size = 2,
+ .skin_devs = {
+ {
+ THERMAL_DEVICE_ID_NCT_EXT,
+ {
+ 2, 1, 1, 1,
+ 1, 1, 1, 1,
+ 1, 1, 1, 0,
+ 1, 1, 0, 0,
+ 0, 0, -1, -7
+ }
+ },
+ {
+ THERMAL_DEVICE_ID_NCT_INT,
+ {
+ -11, -7, -5, -3,
+ -3, -2, -1, 0,
+ 0, 0, 1, 1,
+ 1, 2, 2, 3,
+ 4, 6, 11, 18
+ }
+ },
},
+#endif
};
-static struct resource cardhu_bcm4329_rfkill_resources[] = {
+static struct rfkill_gpio_platform_data cardhu_bt_rfkill_pdata[] = {
{
- .name = "bcm4329_nshutdown_gpio",
- .start = TEGRA_GPIO_PU0,
- .end = TEGRA_GPIO_PU0,
- .flags = IORESOURCE_IO,
+ .name = "bt_rfkill",
+ .shutdown_gpio = TEGRA_GPIO_PU0,
+ .reset_gpio = TEGRA_GPIO_INVALID,
+ .type = RFKILL_TYPE_BLUETOOTH,
},
};
-static struct platform_device cardhu_bcm4329_rfkill_device = {
- .name = "bcm4329_rfkill",
+static struct platform_device cardhu_bt_rfkill_device = {
+ .name = "rfkill_gpio",
.id = -1,
- .num_resources = ARRAY_SIZE(cardhu_bcm4329_rfkill_resources),
- .resource = cardhu_bcm4329_rfkill_resources,
+ .dev = {
+ .platform_data = &cardhu_bt_rfkill_pdata,
+ },
};
static struct resource cardhu_bluesleep_resources[] = {
@@ -172,8 +208,6 @@ static struct platform_device cardhu_bluesleep_device = {
static noinline void __init cardhu_setup_bluesleep(void)
{
platform_device_register(&cardhu_bluesleep_device);
- tegra_gpio_enable(TEGRA_GPIO_PU6);
- tegra_gpio_enable(TEGRA_GPIO_PU1);
return;
}
@@ -200,6 +234,7 @@ static __initdata struct tegra_clk_init_table cardhu_clk_init_table[] = {
{ "i2c3", "pll_p", 3200000, false},
{ "i2c4", "pll_p", 3200000, false},
{ "i2c5", "pll_p", 3200000, false},
+ { "vi", "pll_p", 0, false},
{ NULL, NULL, 0, 0},
};
@@ -228,7 +263,7 @@ static struct tegra_i2c_platform_data cardhu_i2c1_platform_data = {
static struct tegra_i2c_platform_data cardhu_i2c2_platform_data = {
.adapter_nr = 1,
.bus_count = 1,
- .bus_clk_rate = { 100000, 0 },
+ .bus_clk_rate = { 400000, 0 },
.is_clkon_always = true,
.scl_gpio = {TEGRA_GPIO_PT5, 0},
.sda_gpio = {TEGRA_GPIO_PT6, 0},
@@ -728,7 +763,9 @@ static struct platform_device *cardhu_devices[] __initdata = {
#if defined(CONFIG_TEGRA_IOVMM_SMMU) || defined(CONFIG_TEGRA_IOMMU_SMMU)
&tegra_smmu_device,
#endif
- &tegra_wdt_device,
+ &tegra_wdt0_device,
+ &tegra_wdt1_device,
+ &tegra_wdt2_device,
#if defined(CONFIG_TEGRA_AVP)
&tegra_avp_device,
#endif
@@ -747,17 +784,44 @@ static struct platform_device *cardhu_devices[] __initdata = {
&spdif_dit_device,
&bluetooth_dit_device,
&baseband_dit_device,
- &cardhu_bcm4329_rfkill_device,
+ &cardhu_bt_rfkill_device,
&tegra_pcm_device,
&cardhu_audio_wm8903_device,
&cardhu_audio_max98095_device,
&cardhu_audio_aic326x_device,
&tegra_hda_device,
+ &tegra_cec_device,
#if defined(CONFIG_CRYPTO_DEV_TEGRA_AES)
&tegra_aes_device,
#endif
};
+#define E1506_MXT_CONFIG_CRC 0x62F903
+static const u8 e1506_config[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0x32, 0x0A, 0x00, 0x05, 0x01, 0x00,
+ 0x00, 0x1E, 0x0A, 0x8B, 0x00, 0x00, 0x13, 0x0B,
+ 0x00, 0x10, 0x32, 0x03, 0x03, 0x00, 0x03, 0x01,
+ 0x00, 0x0A, 0x0A, 0x0A, 0x0A, 0xBF, 0x03, 0x1B,
+ 0x02, 0x00, 0x00, 0x37, 0x37, 0x00, 0x00, 0x00,
+ 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xA9, 0x7F, 0x9A, 0x0E, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x03, 0x23, 0x00, 0x00, 0x00, 0x0A,
+ 0x0F, 0x14, 0x19, 0x03, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x08, 0x10,
+ 0x00
+};
+
#define MXT_CONFIG_CRC 0xD62DE8
static const u8 config[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -823,6 +887,23 @@ static struct mxt_platform_data atmel_mxt_info = {
.read_chg = NULL,
};
+static struct mxt_platform_data e1506_atmel_mxt_info = {
+ .x_line = 19,
+ .y_line = 11,
+ .x_size = 960,
+ .y_size = 540,
+ .blen = 0x10,
+ .threshold = 0x32,
+ .voltage = 3300000, /* 3.3V */
+ .orient = 3,
+ .config = e1506_config,
+ .config_length = 168,
+ .config_crc = E1506_MXT_CONFIG_CRC,
+ .irqflags = IRQF_TRIGGER_FALLING,
+/* .read_chg = &read_chg, */
+ .read_chg = NULL,
+};
+
static struct i2c_board_info __initdata atmel_i2c_info[] = {
{
I2C_BOARD_INFO("atmel_mxt_ts", 0x5A),
@@ -831,6 +912,14 @@ static struct i2c_board_info __initdata atmel_i2c_info[] = {
}
};
+static struct i2c_board_info __initdata e1506_atmel_i2c_info[] = {
+ {
+ I2C_BOARD_INFO("atmel_mxt_ts", 0x4A),
+ .irq = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PH4),
+ .platform_data = &e1506_atmel_mxt_info,
+ }
+};
+
static __initdata struct tegra_clk_init_table spi_clk_init_table[] = {
/* name parent rate enabled */
{ "sbc1", "pll_p", 52000000, true},
@@ -839,17 +928,15 @@ static __initdata struct tegra_clk_init_table spi_clk_init_table[] = {
static int __init cardhu_touch_init(void)
{
- struct board_info BoardInfo;
+ struct board_info BoardInfo, DisplayBoardInfo;
- tegra_get_display_board_info(&BoardInfo);
- if (BoardInfo.board_id == BOARD_DISPLAY_PM313) {
+ tegra_get_board_info(&BoardInfo);
+ tegra_get_display_board_info(&DisplayBoardInfo);
+ if (DisplayBoardInfo.board_id == BOARD_DISPLAY_PM313) {
tegra_clk_init_from_table(spi_clk_init_table);
touch_init_raydium(TEGRA_GPIO_PH4, TEGRA_GPIO_PH6, 2);
} else {
- tegra_gpio_enable(TEGRA_GPIO_PH4);
- tegra_gpio_enable(TEGRA_GPIO_PH6);
-
gpio_request(TEGRA_GPIO_PH4, "atmel-irq");
gpio_direction_input(TEGRA_GPIO_PH4);
@@ -859,147 +946,305 @@ static int __init cardhu_touch_init(void)
gpio_set_value(TEGRA_GPIO_PH6, 1);
msleep(100);
- tegra_get_board_info(&BoardInfo);
if ((BoardInfo.sku & SKU_TOUCH_MASK) == SKU_TOUCH_2000) {
atmel_mxt_info.config = config_sku2000;
atmel_mxt_info.config_crc = MXT_CONFIG_CRC_SKU2000;
}
- i2c_register_board_info(1, atmel_i2c_info, 1);
+ if (DisplayBoardInfo.board_id == BOARD_DISPLAY_E1506)
+ i2c_register_board_info(1, e1506_atmel_i2c_info, 1);
+ else
+ i2c_register_board_info(1, atmel_i2c_info, 1);
}
return 0;
}
-static struct tegra_uhsic_config uhsic_phy_config = {
- .enable_gpio = EN_HSIC_GPIO,
- .reset_gpio = -1,
- .sync_start_delay = 9,
- .idle_wait_delay = 17,
- .term_range_adj = 0,
- .elastic_underrun_limit = 16,
- .elastic_overrun_limit = 16,
-};
-
-static struct tegra_ehci_platform_data tegra_ehci_uhsic_pdata = {
- .phy_type = TEGRA_USB_PHY_TYPE_HSIC,
- .phy_config = &uhsic_phy_config,
- .operating_mode = TEGRA_USB_HOST,
- .power_down_on_bus_suspend = 1,
- .default_enable = true,
-};
-
-static struct tegra_ehci_platform_data tegra_ehci_pdata[] = {
- [0] = {
- .phy_config = &utmi_phy_config[0],
- .operating_mode = TEGRA_USB_HOST,
- .power_down_on_bus_suspend = 1,
- .default_enable = true,
- },
- [1] = {
- .phy_config = &utmi_phy_config[1],
- .operating_mode = TEGRA_USB_HOST,
- .power_down_on_bus_suspend = 1,
- .default_enable = true,
- },
- [2] = {
- .phy_config = &utmi_phy_config[2],
- .operating_mode = TEGRA_USB_HOST,
- .power_down_on_bus_suspend = 1,
- .hotplug = 1,
- .default_enable = true,
- },
-};
-
-static struct tegra_otg_platform_data tegra_otg_pdata = {
- .ehci_device = &tegra_ehci1_device,
- .ehci_pdata = &tegra_ehci_pdata[0],
-};
-
-#ifdef CONFIG_USB_SUPPORT
-static struct usb_phy_plat_data tegra_usb_phy_pdata[] = {
- [0] = {
- .instance = 0,
- .vbus_gpio = -1,
- .vbus_reg_supply = "vdd_vbus_micro_usb",
- },
- [1] = {
- .instance = 1,
- .vbus_gpio = -1,
- },
- [2] = {
- .instance = 2,
- .vbus_gpio = -1,
- .vbus_reg_supply = "vdd_vbus_typea_usb",
- },
-};
+#if defined(CONFIG_USB_SUPPORT)
-static int cardhu_usb_hsic_postsupend(void)
+static void cardu_usb_hsic_postsupend(void)
{
#ifdef CONFIG_TEGRA_BB_XMM_POWER
baseband_xmm_set_power_status(BBXMM_PS_L2);
#endif
- return 0;
}
-static int cardhu_usb_hsic_preresume(void)
+static void cardu_usb_hsic_preresume(void)
{
#ifdef CONFIG_TEGRA_BB_XMM_POWER
baseband_xmm_set_power_status(BBXMM_PS_L2TOL0);
#endif
- return 0;
}
-static int cardhu_usb_hsic_phy_ready(void)
+static void cardu_usb_hsic_phy_ready(void)
{
#ifdef CONFIG_TEGRA_BB_XMM_POWER
baseband_xmm_set_power_status(BBXMM_PS_L0);
#endif
- return 0;
}
-static int cardhu_usb_hsic_phy_off(void)
+static void cardu_usb_hsic_phy_off(void)
{
#ifdef CONFIG_TEGRA_BB_XMM_POWER
baseband_xmm_set_power_status(BBXMM_PS_L3);
#endif
- return 0;
}
+static struct tegra_usb_phy_platform_ops hsic_xmm_plat_ops = {
+ .post_suspend = cardu_usb_hsic_postsupend,
+ .pre_resume = cardu_usb_hsic_preresume,
+ .port_power = cardu_usb_hsic_phy_ready,
+ .post_phy_off = cardu_usb_hsic_phy_off,
+};
+
+static struct tegra_usb_platform_data tegra_ehci2_hsic_xmm_pdata = {
+ .port_otg = false,
+ .has_hostpc = true,
+ .phy_intf = TEGRA_USB_PHY_INTF_HSIC,
+ .op_mode = TEGRA_USB_OPMODE_HOST,
+ .u_data.host = {
+ .vbus_gpio = -1,
+ .hot_plug = false,
+ .remote_wakeup_supported = false,
+ .power_off_on_suspend = false,
+ },
+ .u_cfg.hsic = {
+ .sync_start_delay = 9,
+ .idle_wait_delay = 17,
+ .term_range_adj = 0,
+ .elastic_underrun_limit = 16,
+ .elastic_overrun_limit = 16,
+ },
+ .ops = &hsic_xmm_plat_ops,
+};
+#endif
+
+static int hsic_enable_gpio = -1;
+static int hsic_reset_gpio = -1;
+
+void hsic_platform_open(void)
+{
+ int reset_gpio = 0, enable_gpio = 0;
+
+ if (hsic_enable_gpio != -1)
+ enable_gpio = gpio_request(hsic_enable_gpio, "uhsic_enable");
+ if (hsic_reset_gpio != -1)
+ reset_gpio = gpio_request(hsic_reset_gpio, "uhsic_reset");
+ /* hsic enable signal deasserted, hsic reset asserted */
+ if (!enable_gpio)
+ gpio_direction_output(hsic_enable_gpio, 0 /* deasserted */);
+ if (!reset_gpio)
+ gpio_direction_output(hsic_reset_gpio, 0 /* asserted */);
+ if (!enable_gpio)
+ tegra_gpio_enable(hsic_enable_gpio);
+ if (!reset_gpio)
+ tegra_gpio_enable(hsic_reset_gpio);
+ /* keep hsic reset asserted for 1 ms */
+ udelay(1000);
+ /* enable (power on) hsic */
+ if (!enable_gpio)
+ gpio_set_value_cansleep(hsic_enable_gpio, 1);
+ udelay(1000);
+ /* deassert reset */
+ if (!reset_gpio)
+ gpio_set_value_cansleep(hsic_reset_gpio, 1);
+
+}
+
+void hsic_platform_close(void)
+{
+ if (hsic_enable_gpio != -1) {
+ gpio_set_value(hsic_enable_gpio, 0);
+ gpio_free(hsic_enable_gpio);
+ }
+ if (hsic_reset_gpio != -1) {
+ gpio_set_value(hsic_reset_gpio, 0);
+ gpio_free(hsic_reset_gpio);
+ }
+}
+
+void hsic_power_on(void)
+{
+ if (hsic_enable_gpio != -1) {
+ gpio_set_value_cansleep(hsic_enable_gpio, 1);
+ udelay(1000);
+ }
+}
+
+void hsic_power_off(void)
+{
+ if (hsic_enable_gpio != -1) {
+ gpio_set_value_cansleep(hsic_enable_gpio, 0);
+ udelay(1000);
+ }
+}
+
+#if defined(CONFIG_USB_SUPPORT)
+static struct tegra_usb_phy_platform_ops hsic_plat_ops = {
+ .open = hsic_platform_open,
+ .close = hsic_platform_close,
+ .pre_phy_on = hsic_power_on,
+ .post_phy_off = hsic_power_off,
+};
+
+static struct tegra_usb_platform_data tegra_ehci2_hsic_pdata = {
+ .port_otg = false,
+ .has_hostpc = true,
+ .phy_intf = TEGRA_USB_PHY_INTF_HSIC,
+ .op_mode = TEGRA_USB_OPMODE_HOST,
+ .u_data.host = {
+ .vbus_gpio = -1,
+ .hot_plug = false,
+ .remote_wakeup_supported = false,
+ .power_off_on_suspend = false,
+ },
+ .u_cfg.hsic = {
+ .sync_start_delay = 9,
+ .idle_wait_delay = 17,
+ .term_range_adj = 0,
+ .elastic_underrun_limit = 16,
+ .elastic_overrun_limit = 16,
+ },
+ .ops = &hsic_plat_ops,
+};
+
+static struct tegra_usb_platform_data tegra_udc_pdata = {
+ .port_otg = true,
+ .has_hostpc = true,
+ .phy_intf = TEGRA_USB_PHY_INTF_UTMI,
+ .op_mode = TEGRA_USB_OPMODE_DEVICE,
+ .u_data.dev = {
+ .vbus_pmu_irq = 0,
+ .vbus_gpio = -1,
+ .charging_supported = false,
+ .remote_wakeup_supported = false,
+ },
+ .u_cfg.utmi = {
+ .hssync_start_delay = 0,
+ .elastic_limit = 16,
+ .idle_wait_delay = 17,
+ .term_range_adj = 6,
+ .xcvr_setup = 8,
+ .xcvr_lsfslew = 2,
+ .xcvr_lsrslew = 2,
+ .xcvr_setup_offset = 0,
+ .xcvr_use_fuses = 1,
+ },
+};
+
+static struct tegra_usb_platform_data tegra_ehci2_utmi_pdata = {
+ .port_otg = false,
+ .has_hostpc = true,
+ .phy_intf = TEGRA_USB_PHY_INTF_UTMI,
+ .op_mode = TEGRA_USB_OPMODE_HOST,
+ .u_data.host = {
+ .vbus_gpio = -1,
+ .hot_plug = false,
+ .remote_wakeup_supported = true,
+ .power_off_on_suspend = true,
+ },
+ .u_cfg.utmi = {
+ .hssync_start_delay = 0,
+ .elastic_limit = 16,
+ .idle_wait_delay = 17,
+ .term_range_adj = 6,
+ .xcvr_setup = 15,
+ .xcvr_lsfslew = 2,
+ .xcvr_lsrslew = 2,
+ .xcvr_setup_offset = 0,
+ .xcvr_use_fuses = 1,
+ },
+};
+
+static struct tegra_usb_platform_data tegra_ehci3_utmi_pdata = {
+ .port_otg = false,
+ .has_hostpc = true,
+ .phy_intf = TEGRA_USB_PHY_INTF_UTMI,
+ .op_mode = TEGRA_USB_OPMODE_HOST,
+ .u_data.host = {
+ .vbus_gpio = -1,
+ .vbus_reg = "vdd_vbus_typea_usb",
+ .hot_plug = true,
+ .remote_wakeup_supported = true,
+ .power_off_on_suspend = true,
+ },
+ .u_cfg.utmi = {
+ .hssync_start_delay = 0,
+ .elastic_limit = 16,
+ .idle_wait_delay = 17,
+ .term_range_adj = 6,
+ .xcvr_setup = 8,
+ .xcvr_lsfslew = 2,
+ .xcvr_lsrslew = 2,
+ .xcvr_setup_offset = 0,
+ .xcvr_use_fuses = 1,
+ },
+};
+
+static struct tegra_usb_platform_data tegra_ehci1_utmi_pdata = {
+ .port_otg = true,
+ .has_hostpc = true,
+ .phy_intf = TEGRA_USB_PHY_INTF_UTMI,
+ .op_mode = TEGRA_USB_OPMODE_HOST,
+ .u_data.host = {
+ .vbus_gpio = -1,
+ .vbus_reg = "vdd_vbus_micro_usb",
+ .hot_plug = true,
+ .remote_wakeup_supported = true,
+ .power_off_on_suspend = true,
+ },
+ .u_cfg.utmi = {
+ .hssync_start_delay = 0,
+ .elastic_limit = 16,
+ .idle_wait_delay = 17,
+ .term_range_adj = 6,
+ .xcvr_setup = 15,
+ .xcvr_lsfslew = 2,
+ .xcvr_lsrslew = 2,
+ .xcvr_setup_offset = 0,
+ .xcvr_use_fuses = 1,
+ },
+};
+
+static struct tegra_usb_otg_data tegra_otg_pdata = {
+ .ehci_device = &tegra_ehci1_device,
+ .ehci_pdata = &tegra_ehci1_utmi_pdata,
+};
+#endif
+
+#if defined(CONFIG_USB_SUPPORT)
static void cardhu_usb_init(void)
{
struct board_info bi;
tegra_get_board_info(&bi);
- tegra_usb_phy_init(tegra_usb_phy_pdata,
- ARRAY_SIZE(tegra_usb_phy_pdata));
-
+ /* OTG should be the first to be registered */
tegra_otg_device.dev.platform_data = &tegra_otg_pdata;
platform_device_register(&tegra_otg_device);
+
+ /* setup the udc platform data */
+ tegra_udc_device.dev.platform_data = &tegra_udc_pdata;
+
if (bi.board_id == BOARD_PM267) {
- uhsic_phy_config.reset_gpio =
- PM267_SMSC4640_HSIC_HUB_RESET_GPIO;
- tegra_ehci2_device.dev.platform_data = &tegra_ehci_uhsic_pdata;
+ hsic_enable_gpio = EN_HSIC_GPIO;
+ hsic_reset_gpio = PM267_SMSC4640_HSIC_HUB_RESET_GPIO;
+ tegra_ehci2_device.dev.platform_data = &tegra_ehci2_hsic_pdata;
platform_device_register(&tegra_ehci2_device);
} else if (bi.board_id == BOARD_E1256) {
- tegra_ehci2_device.dev.platform_data = &tegra_ehci_uhsic_pdata;
+ hsic_enable_gpio = EN_HSIC_GPIO;
+ tegra_ehci2_device.dev.platform_data = &tegra_ehci2_hsic_pdata;
platform_device_register(&tegra_ehci2_device);
} else if (bi.board_id == BOARD_E1186) {
- /* for baseband devices do not switch off phy during suspend */
- tegra_ehci_uhsic_pdata.power_down_on_bus_suspend = 0;
- uhsic_phy_config.postsuspend = cardhu_usb_hsic_postsupend;
- uhsic_phy_config.preresume = cardhu_usb_hsic_preresume;
- uhsic_phy_config.usb_phy_ready = cardhu_usb_hsic_phy_ready;
- uhsic_phy_config.post_phy_off = cardhu_usb_hsic_phy_off;
- tegra_ehci2_device.dev.platform_data = &tegra_ehci_uhsic_pdata;
- /* baseband registration happens in baseband-xmm-power */
+ tegra_ehci2_device.dev.platform_data =
+ &tegra_ehci2_hsic_xmm_pdata;
+ /* ehci2 registration happens in baseband-xmm-power */
} else {
- tegra_ehci2_device.dev.platform_data = &tegra_ehci_pdata[1];
+ tegra_ehci2_device.dev.platform_data = &tegra_ehci2_utmi_pdata;
platform_device_register(&tegra_ehci2_device);
}
- tegra_ehci3_device.dev.platform_data = &tegra_ehci_pdata[2];
+ tegra_ehci3_device.dev.platform_data = &tegra_ehci3_utmi_pdata;
platform_device_register(&tegra_ehci3_device);
}
@@ -1007,19 +1252,6 @@ static void cardhu_usb_init(void)
static void cardhu_usb_init(void) { }
#endif
-static void cardhu_gps_init(void)
-{
- tegra_gpio_enable(TEGRA_GPIO_PU2);
- tegra_gpio_enable(TEGRA_GPIO_PU3);
-}
-
-static void cardhu_nfc_init(void)
-{
- tegra_gpio_enable(TEGRA_GPIO_PX0);
- tegra_gpio_enable(TEGRA_GPIO_PP3);
- tegra_gpio_enable(TEGRA_GPIO_PO7);
-}
-
static struct baseband_power_platform_data tegra_baseband_power_data = {
.baseband_type = BASEBAND_XMM,
.modem = {
@@ -1097,7 +1329,7 @@ static void cardhu_modem_init(void)
} else {
w_disable_gpio = TEGRA_GPIO_PDD5;
}
- tegra_gpio_enable(w_disable_gpio);
+
ret = gpio_request(w_disable_gpio, "w_disable_gpio");
if (ret < 0)
pr_err("%s: gpio_request failed for gpio %d\n",
@@ -1117,22 +1349,9 @@ static void cardhu_modem_init(void)
break;
}
gpio_direction_output(TEGRA_GPIO_PH7, 1);
- tegra_gpio_enable(TEGRA_GPIO_PH7);
}
break;
case BOARD_E1186:
- tegra_gpio_enable(
- tegra_baseband_power_data.modem.xmm.bb_rst);
- tegra_gpio_enable(
- tegra_baseband_power_data.modem.xmm.bb_on);
- tegra_gpio_enable(
- tegra_baseband_power_data.modem.xmm.ipc_bb_wake);
- tegra_gpio_enable(
- tegra_baseband_power_data.modem.xmm.ipc_ap_wake);
- tegra_gpio_enable(
- tegra_baseband_power_data.modem.xmm.ipc_hsic_active);
- tegra_gpio_enable(
- tegra_baseband_power_data.modem.xmm.ipc_hsic_sus_req);
platform_device_register(&tegra_baseband_power_device);
platform_device_register(&tegra_baseband_power2_device);
break;
@@ -1153,7 +1372,9 @@ static void cardhu_sata_init(void) { }
static void __init tegra_cardhu_init(void)
{
- tegra_thermal_init(&thermal_data);
+ tegra_thermal_init(&thermal_data,
+ throttle_list,
+ ARRAY_SIZE(throttle_list));
tegra_clk_init_from_table(cardhu_clk_init_table);
cardhu_pinmux_init();
cardhu_i2c_init();
@@ -1170,7 +1391,6 @@ static void __init tegra_cardhu_init(void)
cardhu_dtv_init();
cardhu_suspend_init();
cardhu_touch_init();
- cardhu_gps_init();
cardhu_modem_init();
cardhu_kbc_init();
cardhu_scroll_init();
@@ -1184,18 +1404,18 @@ static void __init tegra_cardhu_init(void)
cardhu_pins_state_init();
cardhu_emc_init();
tegra_release_bootloader_fb();
- cardhu_nfc_init();
cardhu_pci_init();
#ifdef CONFIG_TEGRA_WDT_RECOVERY
tegra_wdt_recovery_init();
#endif
+ tegra_serial_debug_init(TEGRA_UARTD_BASE, INT_WDT_CPU, NULL, -1, -1);
}
static void __init tegra_cardhu_reserve(void)
{
#if defined(CONFIG_NVMAP_CONVERT_CARVEOUT_TO_IOVMM)
- /* support 1920X1200 with 24bpp */
- tegra_reserve(0, SZ_8M + SZ_1M, SZ_8M + SZ_1M);
+ /* Support 1920X1080 32bpp,double buffered on HDMI*/
+ tegra_reserve(0, SZ_8M + SZ_1M, SZ_16M);
#else
tegra_reserve(SZ_128M, SZ_8M, SZ_8M);
#endif
diff --git a/arch/arm/mach-tegra/board-cardhu.h b/arch/arm/mach-tegra/board-cardhu.h
index ba2a0d05b46c..a8be32ec9cdd 100644
--- a/arch/arm/mach-tegra/board-cardhu.h
+++ b/arch/arm/mach-tegra/board-cardhu.h
@@ -76,10 +76,15 @@
#define BOARD_FAB_A03 0x3
#define BOARD_FAB_A04 0x4
#define BOARD_FAB_A05 0x5
+#define BOARD_FAB_A06 0x6
+#define BOARD_FAB_A07 0x7
/* Display Board ID */
#define BOARD_DISPLAY_PM313 0x030D
+#define BOARD_DISPLAY_E1213 0x0C0D
#define BOARD_DISPLAY_E1247 0x0C2F
+#define BOARD_DISPLAY_E1253 0x0C35
+#define BOARD_DISPLAY_E1506 0x0F06
/* External peripheral act as gpio */
/* TPS6591x GPIOs */
diff --git a/arch/arm/mach-tegra/board-enterprise-baseband.c b/arch/arm/mach-tegra/board-enterprise-baseband.c
index 7552e2871541..c73a7ad5e5b4 100644
--- a/arch/arm/mach-tegra/board-enterprise-baseband.c
+++ b/arch/arm/mach-tegra/board-enterprise-baseband.c
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/board-enterprise-baseband.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
@@ -22,15 +22,8 @@
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/gpio.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
#include <linux/err.h>
-#include <linux/wakelock.h>
#include <linux/platform_data/tegra_usb.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <mach/pinmux.h>
-#include <mach/usb_phy.h>
#include <mach/tegra_usb_modem_power.h>
#include "devices.h"
#include "gpio-names.h"
@@ -40,111 +33,63 @@
#define MODEM_RESET TEGRA_GPIO_PE1
#define BB_RST_OUT TEGRA_GPIO_PV1
-/* Icera BB GPIO */
+/* Icera modem handshaking GPIO */
#define AP2MDM_ACK TEGRA_GPIO_PE3
#define MDM2AP_ACK TEGRA_GPIO_PU5
#define AP2MDM_ACK2 TEGRA_GPIO_PE2
#define MDM2AP_ACK2 TEGRA_GPIO_PV0
-/* ULPI GPIO */
-#define ULPI_STP TEGRA_GPIO_PY3
-#define ULPI_DIR TEGRA_GPIO_PY1
-#define ULPI_D0 TEGRA_GPIO_PO1
-#define ULPI_D1 TEGRA_GPIO_PO2
-
-static struct wake_lock mdm_wake_lock;
-
static struct gpio modem_gpios[] = {
{MODEM_PWR_ON, GPIOF_OUT_INIT_LOW, "MODEM PWR ON"},
{MODEM_RESET, GPIOF_IN, "MODEM RESET"},
- {BB_RST_OUT, GPIOF_IN, "BB RST OUT"},
- {MDM2AP_ACK, GPIOF_IN, "MDM2AP_ACK"},
{AP2MDM_ACK2, GPIOF_OUT_INIT_HIGH, "AP2MDM ACK2"},
{AP2MDM_ACK, GPIOF_OUT_INIT_LOW, "AP2MDM ACK"},
- {ULPI_STP, GPIOF_IN, "ULPI_STP"},
- {ULPI_DIR, GPIOF_OUT_INIT_LOW, "ULPI_DIR"},
- {ULPI_D0, GPIOF_OUT_INIT_LOW, "ULPI_D0"},
- {ULPI_D1, GPIOF_OUT_INIT_LOW, "ULPI_D1"},
};
-static int baseband_phy_on(void);
-static int baseband_phy_off(void);
-static void baseband_phy_restore_start(void);
-static void baseband_phy_restore_end(void);
-
-static struct tegra_ulpi_trimmer e1219_trimmer = { 10, 1, 1, 1 };
-
-static struct tegra_ulpi_config ehci2_null_ulpi_phy_config = {
- .trimmer = &e1219_trimmer,
- .post_phy_on = baseband_phy_on,
- .pre_phy_off = baseband_phy_off,
- .phy_restore_start = baseband_phy_restore_start,
- .phy_restore_end = baseband_phy_restore_end,
- .phy_restore_gpio = MDM2AP_ACK,
- .ulpi_dir_gpio = ULPI_DIR,
- .ulpi_d0_gpio = ULPI_D0,
- .ulpi_d1_gpio = ULPI_D1,
-};
+static void baseband_post_phy_on(void);
+static void baseband_pre_phy_off(void);
-static struct tegra_ehci_platform_data ehci2_null_ulpi_platform_data = {
- .operating_mode = TEGRA_USB_HOST,
- .power_down_on_bus_suspend = 0,
- .phy_config = &ehci2_null_ulpi_phy_config,
- .phy_type = TEGRA_USB_PHY_TYPE_NULL_ULPI,
+static struct tegra_usb_phy_platform_ops ulpi_null_plat_ops = {
+ .pre_phy_off = baseband_pre_phy_off,
+ .post_phy_on = baseband_post_phy_on,
};
-static int __init tegra_null_ulpi_init(void)
-{
- tegra_ehci2_device.dev.platform_data = &ehci2_null_ulpi_platform_data;
- platform_device_register(&tegra_ehci2_device);
- return 0;
-}
-
-static irqreturn_t mdm_start_thread(int irq, void *data)
-{
- if (gpio_get_value(BB_RST_OUT)) {
- pr_info("BB_RST_OUT high\n");
- } else {
- pr_info("BB_RST_OUT low\n");
- }
-
- /* hold wait lock to complete the enumeration */
- wake_lock_timeout(&mdm_wake_lock, HZ * 10);
-
- return IRQ_HANDLED;
-}
-
-static int baseband_phy_on(void)
-{
- static bool phy_init = false;
-
- if (!phy_init) {
- /* set AP2MDM_ACK2 low */
- gpio_set_value(AP2MDM_ACK2, 0);
- phy_init = true;
- }
- pr_info("%s\n", __func__);
- return 0;
-}
+static struct tegra_usb_platform_data tegra_ehci2_ulpi_null_pdata = {
+ .port_otg = false,
+ .has_hostpc = true,
+ .phy_intf = TEGRA_USB_PHY_INTF_ULPI_NULL,
+ .op_mode = TEGRA_USB_OPMODE_HOST,
+ .u_data.host = {
+ .vbus_gpio = -1,
+ .vbus_reg = NULL,
+ .hot_plug = true,
+ .remote_wakeup_supported = false,
+ .power_off_on_suspend = true,
+ },
+ .u_cfg.ulpi = {
+ .shadow_clk_delay = 10,
+ .clock_out_delay = 1,
+ .data_trimmer = 1,
+ .stpdirnxt_trimmer = 1,
+ .dir_trimmer = 1,
+ .clk = NULL,
+ .phy_restore_gpio = MDM2AP_ACK,
+ },
+ .ops = &ulpi_null_plat_ops,
+};
-static int baseband_phy_off(void)
+static void baseband_post_phy_on(void)
{
- pr_info("%s\n", __func__);
- return 0;
+ /* set AP2MDM_ACK2 low */
+ gpio_set_value(AP2MDM_ACK2, 0);
}
-static void baseband_phy_restore_start(void)
+static void baseband_pre_phy_off(void)
{
/* set AP2MDM_ACK2 high */
gpio_set_value(AP2MDM_ACK2, 1);
}
-static void baseband_phy_restore_end(void)
-{
- /* set AP2MDM_ACK2 low */
- gpio_set_value(AP2MDM_ACK2, 0);
-}
-
static void baseband_start(void)
{
/*
@@ -166,7 +111,6 @@ static void baseband_reset(void)
static int baseband_init(void)
{
- int irq;
int ret;
ret = gpio_request_array(modem_gpios, ARRAY_SIZE(modem_gpios));
@@ -181,42 +125,9 @@ static int baseband_init(void)
tegra_pinmux_set_pullupdown(TEGRA_PINGROUP_GPIO_PV0,
TEGRA_PUPD_PULL_UP);
- tegra_gpio_enable(MODEM_PWR_ON);
- tegra_gpio_enable(MODEM_RESET);
- tegra_gpio_enable(AP2MDM_ACK2);
- tegra_gpio_enable(BB_RST_OUT);
- tegra_gpio_enable(AP2MDM_ACK);
- tegra_gpio_enable(MDM2AP_ACK);
- tegra_gpio_enable(TEGRA_GPIO_PY3);
- tegra_gpio_enable(TEGRA_GPIO_PO1);
- tegra_gpio_enable(TEGRA_GPIO_PO2);
-
/* export GPIO for user space access through sysfs */
gpio_export(MODEM_PWR_ON, false);
- /* phy init */
- tegra_null_ulpi_init();
-
- wake_lock_init(&mdm_wake_lock, WAKE_LOCK_SUSPEND, "mdm_lock");
-
- /* enable IRQ for BB_RST_OUT */
- irq = gpio_to_irq(BB_RST_OUT);
-
- ret = request_threaded_irq(irq, NULL, mdm_start_thread,
- IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
- "mdm_start", NULL);
- if (ret < 0) {
- pr_err("%s: request_threaded_irq error\n", __func__);
- return ret;
- }
-
- ret = enable_irq_wake(irq);
- if (ret) {
- pr_err("%s: enable_irq_wake error\n", __func__);
- free_irq(irq, NULL);
- return ret;
- }
-
return 0;
}
@@ -229,7 +140,13 @@ static const struct tegra_modem_operations baseband_operations = {
static struct tegra_usb_modem_power_platform_data baseband_pdata = {
.ops = &baseband_operations,
.wake_gpio = MDM2AP_ACK2,
- .flags = IRQF_TRIGGER_FALLING,
+ .wake_irq_flags = IRQF_TRIGGER_FALLING,
+ .boot_gpio = BB_RST_OUT,
+ .boot_irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ .autosuspend_delay = 2000,
+ .short_autosuspend_delay = 50,
+ .tegra_ehci_device = &tegra_ehci2_device,
+ .tegra_ehci_pdata = &tegra_ehci2_ulpi_null_pdata,
};
static struct platform_device icera_baseband_device = {
diff --git a/arch/arm/mach-tegra/board-enterprise-memory.c b/arch/arm/mach-tegra/board-enterprise-memory.c
index fca1a08ed701..36a8264c2a21 100644
--- a/arch/arm/mach-tegra/board-enterprise-memory.c
+++ b/arch/arm/mach-tegra/board-enterprise-memory.c
@@ -24,7 +24,7 @@
#include "board.h"
-static const struct tegra_emc_table enterprise_emc_tables_h5tc2g[] = {
+static const struct tegra_emc_table enterprise_emc_tables_kmmll0_a02[] = {
{
0x32, /* Rev 3.2 */
12750, /* SDRAM frequency */
@@ -717,7 +717,7 @@ static const struct tegra_emc_table enterprise_emc_tables_h5tc2g[] = {
0x00000000, /* EMC_CTT_DURATION */
0x80000ce6, /* EMC_DYN_SELF_REF_CONTROL */
0x00000006, /* MC_EMEM_ARB_CFG */
- 0x80000048, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0xc0000048, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000002, /* MC_EMEM_ARB_TIMING_RCD */
0x00000003, /* MC_EMEM_ARB_TIMING_RP */
0x0000000c, /* MC_EMEM_ARB_TIMING_RC */
@@ -747,6 +747,729 @@ static const struct tegra_emc_table enterprise_emc_tables_h5tc2g[] = {
},
};
+static const struct tegra_emc_table enterprise_emc_tables_kmkts0_a03[] = {
+ {
+ 0x32, /* Rev 3.2 */
+ 12750, /* SDRAM frequency */
+ {
+ 0x00000000, /* EMC_RC */
+ 0x00000001, /* EMC_RFC */
+ 0x00000002, /* EMC_RAS */
+ 0x00000002, /* EMC_RP */
+ 0x00000004, /* EMC_R2W */
+ 0x00000004, /* EMC_W2R */
+ 0x00000001, /* EMC_R2P */
+ 0x00000005, /* EMC_W2P */
+ 0x00000002, /* EMC_RD_RCD */
+ 0x00000002, /* EMC_WR_RCD */
+ 0x00000001, /* EMC_RRD */
+ 0x00000001, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000001, /* EMC_WDV */
+ 0x00000003, /* EMC_QUSE */
+ 0x00000001, /* EMC_QRST */
+ 0x0000000b, /* EMC_QSAFE */
+ 0x0000000a, /* EMC_RDV */
+ 0x0000002f, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x0000000b, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x00000001, /* EMC_PDEX2WR */
+ 0x00000001, /* EMC_PDEX2RD */
+ 0x00000002, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x00000001, /* EMC_AR2PDEN */
+ 0x00000007, /* EMC_RW2PDEN */
+ 0x00000002, /* EMC_TXSR */
+ 0x00000002, /* EMC_TXSRDLL */
+ 0x00000003, /* EMC_TCKE */
+ 0x00000008, /* EMC_TFAW */
+ 0x00000004, /* EMC_TRPAB */
+ 0x00000001, /* EMC_TCLKSTABLE */
+ 0x00000002, /* EMC_TCLKSTOP */
+ 0x00000036, /* EMC_TREFBW */
+ 0x00000004, /* EMC_QUSE_EXTRA */
+ 0x00000006, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00004282, /* EMC_FBIO_CFG5 */
+ 0x007800a4, /* EMC_CFG_DIG_DLL */
+ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS0 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS1 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS2 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS3 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS4 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS5 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS6 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS7 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE3 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE4 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE5 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE6 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE7 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQ0 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQ1 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQ2 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQ3 */
+ 0x00100220, /* EMC_XM2CMDPADCTRL */
+ 0x0800201c, /* EMC_XM2DQSPADCTRL2 */
+ 0x00000000, /* EMC_XM2DQPADCTRL2 */
+ 0x77ffc004, /* EMC_XM2CLKPADCTRL */
+ 0x01f1f008, /* EMC_XM2COMPPADCTRL */
+ 0x00000000, /* EMC_XM2VTTGENPADCTRL */
+ 0x00000007, /* EMC_XM2VTTGENPADCTRL2 */
+ 0x08000068, /* EMC_XM2QUSEPADCTRL */
+ 0x08000000, /* EMC_XM2DQSPADCTRL3 */
+ 0x00000802, /* EMC_CTT_TERM_CTRL */
+ 0x00064000, /* EMC_ZCAL_INTERVAL */
+ 0x00000009, /* EMC_ZCAL_WAIT_CNT */
+ 0x00090009, /* EMC_MRS_WAIT_CNT */
+ 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */
+ 0x00000000, /* EMC_CTT */
+ 0x00000000, /* EMC_CTT_DURATION */
+ 0x80000164, /* EMC_DYN_SELF_REF_CONTROL */
+ 0x00050001, /* MC_EMEM_ARB_CFG */
+ 0xc0000008, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RP */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RC */
+ 0x00000000, /* MC_EMEM_ARB_TIMING_RAS */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_FAW */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */
+ 0x00000004, /* MC_EMEM_ARB_TIMING_WAP2PRE */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_R2R */
+ 0x00000000, /* MC_EMEM_ARB_TIMING_W2W */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_R2W */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_W2R */
+ 0x02020001, /* MC_EMEM_ARB_DA_TURNS */
+ 0x00060402, /* MC_EMEM_ARB_DA_COVERS */
+ 0x77230303, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0xe0000000, /* EMC_FBIO_SPARE */
+ 0xff00ff00, /* EMC_CFG_RSV */
+ },
+ 0x00000009, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000001, /* EMC_CFG.PERIODIC_QRST */
+ 0x00000000, /* Mode Register 0 */
+ 0x00010022, /* Mode Register 1 */
+ 0x00020001, /* Mode Register 2 */
+ 0x00000001, /* EMC_CFG.DYN_SELF_REF */
+ },
+ {
+ 0x32, /* Rev 3.2 */
+ 25500, /* SDRAM frequency */
+ {
+ 0x00000001, /* EMC_RC */
+ 0x00000003, /* EMC_RFC */
+ 0x00000002, /* EMC_RAS */
+ 0x00000002, /* EMC_RP */
+ 0x00000004, /* EMC_R2W */
+ 0x00000004, /* EMC_W2R */
+ 0x00000001, /* EMC_R2P */
+ 0x00000005, /* EMC_W2P */
+ 0x00000002, /* EMC_RD_RCD */
+ 0x00000002, /* EMC_WR_RCD */
+ 0x00000001, /* EMC_RRD */
+ 0x00000001, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000001, /* EMC_WDV */
+ 0x00000003, /* EMC_QUSE */
+ 0x00000001, /* EMC_QRST */
+ 0x0000000b, /* EMC_QSAFE */
+ 0x0000000a, /* EMC_RDV */
+ 0x00000060, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x00000018, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x00000001, /* EMC_PDEX2WR */
+ 0x00000001, /* EMC_PDEX2RD */
+ 0x00000002, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x00000001, /* EMC_AR2PDEN */
+ 0x00000007, /* EMC_RW2PDEN */
+ 0x00000004, /* EMC_TXSR */
+ 0x00000004, /* EMC_TXSRDLL */
+ 0x00000003, /* EMC_TCKE */
+ 0x00000008, /* EMC_TFAW */
+ 0x00000004, /* EMC_TRPAB */
+ 0x00000001, /* EMC_TCLKSTABLE */
+ 0x00000002, /* EMC_TCLKSTOP */
+ 0x0000006b, /* EMC_TREFBW */
+ 0x00000004, /* EMC_QUSE_EXTRA */
+ 0x00000006, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00004282, /* EMC_FBIO_CFG5 */
+ 0x007800a4, /* EMC_CFG_DIG_DLL */
+ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS0 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS1 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS2 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS3 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS4 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS5 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS6 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS7 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE3 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE4 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE5 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE6 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE7 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQ0 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQ1 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQ2 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQ3 */
+ 0x00100220, /* EMC_XM2CMDPADCTRL */
+ 0x0800201c, /* EMC_XM2DQSPADCTRL2 */
+ 0x00000000, /* EMC_XM2DQPADCTRL2 */
+ 0x77ffc004, /* EMC_XM2CLKPADCTRL */
+ 0x01f1f008, /* EMC_XM2COMPPADCTRL */
+ 0x00000000, /* EMC_XM2VTTGENPADCTRL */
+ 0x00000007, /* EMC_XM2VTTGENPADCTRL2 */
+ 0x08000068, /* EMC_XM2QUSEPADCTRL */
+ 0x08000000, /* EMC_XM2DQSPADCTRL3 */
+ 0x00000802, /* EMC_CTT_TERM_CTRL */
+ 0x00064000, /* EMC_ZCAL_INTERVAL */
+ 0x0000000a, /* EMC_ZCAL_WAIT_CNT */
+ 0x00090009, /* EMC_MRS_WAIT_CNT */
+ 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */
+ 0x00000000, /* EMC_CTT */
+ 0x00000000, /* EMC_CTT_DURATION */
+ 0x800001c5, /* EMC_DYN_SELF_REF_CONTROL */
+ 0x00020001, /* MC_EMEM_ARB_CFG */
+ 0xc0000008, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RP */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RC */
+ 0x00000000, /* MC_EMEM_ARB_TIMING_RAS */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_FAW */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */
+ 0x00000004, /* MC_EMEM_ARB_TIMING_WAP2PRE */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_R2R */
+ 0x00000000, /* MC_EMEM_ARB_TIMING_W2W */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_R2W */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_W2R */
+ 0x02020001, /* MC_EMEM_ARB_DA_TURNS */
+ 0x00060402, /* MC_EMEM_ARB_DA_COVERS */
+ 0x73e30303, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0xe0000000, /* EMC_FBIO_SPARE */
+ 0xff00ff00, /* EMC_CFG_RSV */
+ },
+ 0x00000009, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000001, /* EMC_CFG.PERIODIC_QRST */
+ 0x00000000, /* Mode Register 0 */
+ 0x00010022, /* Mode Register 1 */
+ 0x00020001, /* Mode Register 2 */
+ 0x00000001, /* EMC_CFG.DYN_SELF_REF */
+ },
+ {
+ 0x32, /* Rev 3.2 */
+ 51000, /* SDRAM frequency */
+ {
+ 0x00000003, /* EMC_RC */
+ 0x00000006, /* EMC_RFC */
+ 0x00000002, /* EMC_RAS */
+ 0x00000002, /* EMC_RP */
+ 0x00000004, /* EMC_R2W */
+ 0x00000004, /* EMC_W2R */
+ 0x00000001, /* EMC_R2P */
+ 0x00000005, /* EMC_W2P */
+ 0x00000002, /* EMC_RD_RCD */
+ 0x00000002, /* EMC_WR_RCD */
+ 0x00000001, /* EMC_RRD */
+ 0x00000001, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000001, /* EMC_WDV */
+ 0x00000003, /* EMC_QUSE */
+ 0x00000001, /* EMC_QRST */
+ 0x0000000b, /* EMC_QSAFE */
+ 0x0000000a, /* EMC_RDV */
+ 0x000000c0, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x00000030, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x00000001, /* EMC_PDEX2WR */
+ 0x00000001, /* EMC_PDEX2RD */
+ 0x00000002, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x00000001, /* EMC_AR2PDEN */
+ 0x00000007, /* EMC_RW2PDEN */
+ 0x00000008, /* EMC_TXSR */
+ 0x00000008, /* EMC_TXSRDLL */
+ 0x00000003, /* EMC_TCKE */
+ 0x00000008, /* EMC_TFAW */
+ 0x00000004, /* EMC_TRPAB */
+ 0x00000001, /* EMC_TCLKSTABLE */
+ 0x00000002, /* EMC_TCLKSTOP */
+ 0x000000d5, /* EMC_TREFBW */
+ 0x00000004, /* EMC_QUSE_EXTRA */
+ 0x00000006, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00004282, /* EMC_FBIO_CFG5 */
+ 0x007800a4, /* EMC_CFG_DIG_DLL */
+ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS0 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS1 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS2 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS3 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS4 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS5 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS6 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS7 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE3 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE4 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE5 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE6 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE7 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQ0 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQ1 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQ2 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQ3 */
+ 0x00100220, /* EMC_XM2CMDPADCTRL */
+ 0x0800201c, /* EMC_XM2DQSPADCTRL2 */
+ 0x00000000, /* EMC_XM2DQPADCTRL2 */
+ 0x77ffc004, /* EMC_XM2CLKPADCTRL */
+ 0x01f1f008, /* EMC_XM2COMPPADCTRL */
+ 0x00000000, /* EMC_XM2VTTGENPADCTRL */
+ 0x00000007, /* EMC_XM2VTTGENPADCTRL2 */
+ 0x08000068, /* EMC_XM2QUSEPADCTRL */
+ 0x08000000, /* EMC_XM2DQSPADCTRL3 */
+ 0x00000802, /* EMC_CTT_TERM_CTRL */
+ 0x00064000, /* EMC_ZCAL_INTERVAL */
+ 0x00000013, /* EMC_ZCAL_WAIT_CNT */
+ 0x00090009, /* EMC_MRS_WAIT_CNT */
+ 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */
+ 0x00000000, /* EMC_CTT */
+ 0x00000000, /* EMC_CTT_DURATION */
+ 0x80000287, /* EMC_DYN_SELF_REF_CONTROL */
+ 0x00010001, /* MC_EMEM_ARB_CFG */
+ 0xc000000a, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RP */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RC */
+ 0x00000000, /* MC_EMEM_ARB_TIMING_RAS */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_FAW */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */
+ 0x00000004, /* MC_EMEM_ARB_TIMING_WAP2PRE */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_R2R */
+ 0x00000000, /* MC_EMEM_ARB_TIMING_W2W */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_R2W */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_W2R */
+ 0x02020001, /* MC_EMEM_ARB_DA_TURNS */
+ 0x00060402, /* MC_EMEM_ARB_DA_COVERS */
+ 0x72c30303, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0xe0000000, /* EMC_FBIO_SPARE */
+ 0xff00ff00, /* EMC_CFG_RSV */
+ },
+ 0x00000009, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000001, /* EMC_CFG.PERIODIC_QRST */
+ 0x00000000, /* Mode Register 0 */
+ 0x00010022, /* Mode Register 1 */
+ 0x00020001, /* Mode Register 2 */
+ 0x00000001, /* EMC_CFG.DYN_SELF_REF */
+ },
+ {
+ 0x32, /* Rev 3.2 */
+ 102000, /* SDRAM frequency */
+ {
+ 0x00000006, /* EMC_RC */
+ 0x0000000d, /* EMC_RFC */
+ 0x00000004, /* EMC_RAS */
+ 0x00000002, /* EMC_RP */
+ 0x00000004, /* EMC_R2W */
+ 0x00000004, /* EMC_W2R */
+ 0x00000002, /* EMC_R2P */
+ 0x00000005, /* EMC_W2P */
+ 0x00000002, /* EMC_RD_RCD */
+ 0x00000002, /* EMC_WR_RCD */
+ 0x00000001, /* EMC_RRD */
+ 0x00000001, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000001, /* EMC_WDV */
+ 0x00000003, /* EMC_QUSE */
+ 0x00000001, /* EMC_QRST */
+ 0x0000000b, /* EMC_QSAFE */
+ 0x0000000a, /* EMC_RDV */
+ 0x00000181, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x00000060, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x00000001, /* EMC_PDEX2WR */
+ 0x00000001, /* EMC_PDEX2RD */
+ 0x00000002, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x00000001, /* EMC_AR2PDEN */
+ 0x00000007, /* EMC_RW2PDEN */
+ 0x0000000f, /* EMC_TXSR */
+ 0x0000000f, /* EMC_TXSRDLL */
+ 0x00000003, /* EMC_TCKE */
+ 0x00000008, /* EMC_TFAW */
+ 0x00000004, /* EMC_TRPAB */
+ 0x00000001, /* EMC_TCLKSTABLE */
+ 0x00000002, /* EMC_TCLKSTOP */
+ 0x000001a9, /* EMC_TREFBW */
+ 0x00000004, /* EMC_QUSE_EXTRA */
+ 0x00000006, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00004282, /* EMC_FBIO_CFG5 */
+ 0x007800a4, /* EMC_CFG_DIG_DLL */
+ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS0 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS1 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS2 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS3 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS4 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS5 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS6 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQS7 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE3 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE4 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE5 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE6 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE7 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQ0 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQ1 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQ2 */
+ 0x000fc000, /* EMC_DLL_XFORM_DQ3 */
+ 0x00100220, /* EMC_XM2CMDPADCTRL */
+ 0x0800201c, /* EMC_XM2DQSPADCTRL2 */
+ 0x00000000, /* EMC_XM2DQPADCTRL2 */
+ 0x77ffc004, /* EMC_XM2CLKPADCTRL */
+ 0x01f1f008, /* EMC_XM2COMPPADCTRL */
+ 0x00000000, /* EMC_XM2VTTGENPADCTRL */
+ 0x00000007, /* EMC_XM2VTTGENPADCTRL2 */
+ 0x08000068, /* EMC_XM2QUSEPADCTRL */
+ 0x08000000, /* EMC_XM2DQSPADCTRL3 */
+ 0x00000802, /* EMC_CTT_TERM_CTRL */
+ 0x00000000, /* EMC_ZCAL_INTERVAL */
+ 0x0000000a, /* EMC_ZCAL_WAIT_CNT */
+ 0x00090009, /* EMC_MRS_WAIT_CNT */
+ 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */
+ 0x00000000, /* EMC_CTT */
+ 0x00000000, /* EMC_CTT_DURATION */
+ 0x8000040b, /* EMC_DYN_SELF_REF_CONTROL */
+ 0x00000001, /* MC_EMEM_ARB_CFG */
+ 0xc0000013, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RP */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_RC */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RAS */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_FAW */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */
+ 0x00000004, /* MC_EMEM_ARB_TIMING_WAP2PRE */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_R2R */
+ 0x00000000, /* MC_EMEM_ARB_TIMING_W2W */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_R2W */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_W2R */
+ 0x02020001, /* MC_EMEM_ARB_DA_TURNS */
+ 0x00060403, /* MC_EMEM_ARB_DA_COVERS */
+ 0x72430504, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0xe0000000, /* EMC_FBIO_SPARE */
+ 0xff00ff00, /* EMC_CFG_RSV */
+ },
+ 0x0000000a, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000001, /* EMC_CFG.PERIODIC_QRST */
+ 0x00000000, /* Mode Register 0 */
+ 0x00010022, /* Mode Register 1 */
+ 0x00020001, /* Mode Register 2 */
+ 0x00000001, /* EMC_CFG.DYN_SELF_REF */
+ },
+ {
+ 0x32, /* Rev 3.2 */
+ 204000, /* SDRAM frequency */
+ {
+ 0x0000000c, /* EMC_RC */
+ 0x0000001a, /* EMC_RFC */
+ 0x00000008, /* EMC_RAS */
+ 0x00000003, /* EMC_RP */
+ 0x00000005, /* EMC_R2W */
+ 0x00000004, /* EMC_W2R */
+ 0x00000002, /* EMC_R2P */
+ 0x00000006, /* EMC_W2P */
+ 0x00000003, /* EMC_RD_RCD */
+ 0x00000003, /* EMC_WR_RCD */
+ 0x00000002, /* EMC_RRD */
+ 0x00000002, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000001, /* EMC_WDV */
+ 0x00000003, /* EMC_QUSE */
+ 0x00000001, /* EMC_QRST */
+ 0x0000000c, /* EMC_QSAFE */
+ 0x0000000b, /* EMC_RDV */
+ 0x00000303, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x000000c0, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x00000001, /* EMC_PDEX2WR */
+ 0x00000001, /* EMC_PDEX2RD */
+ 0x00000003, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x00000001, /* EMC_AR2PDEN */
+ 0x00000007, /* EMC_RW2PDEN */
+ 0x0000001d, /* EMC_TXSR */
+ 0x0000001d, /* EMC_TXSRDLL */
+ 0x00000004, /* EMC_TCKE */
+ 0x0000000b, /* EMC_TFAW */
+ 0x00000005, /* EMC_TRPAB */
+ 0x00000001, /* EMC_TCLKSTABLE */
+ 0x00000002, /* EMC_TCLKSTOP */
+ 0x00000351, /* EMC_TREFBW */
+ 0x00000004, /* EMC_QUSE_EXTRA */
+ 0x00000006, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00004282, /* EMC_FBIO_CFG5 */
+ 0x004400a4, /* EMC_CFG_DIG_DLL */
+ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */
+ 0x0007c000, /* EMC_DLL_XFORM_DQS0 */
+ 0x0007c000, /* EMC_DLL_XFORM_DQS1 */
+ 0x0007c000, /* EMC_DLL_XFORM_DQS2 */
+ 0x0007c000, /* EMC_DLL_XFORM_DQS3 */
+ 0x00072000, /* EMC_DLL_XFORM_DQS4 */
+ 0x00072000, /* EMC_DLL_XFORM_DQS5 */
+ 0x00072000, /* EMC_DLL_XFORM_DQS6 */
+ 0x00072000, /* EMC_DLL_XFORM_DQS7 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE3 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE4 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE5 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE6 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE7 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */
+ 0x00088000, /* EMC_DLL_XFORM_DQ0 */
+ 0x00088000, /* EMC_DLL_XFORM_DQ1 */
+ 0x00088000, /* EMC_DLL_XFORM_DQ2 */
+ 0x00088000, /* EMC_DLL_XFORM_DQ3 */
+ 0x000e0220, /* EMC_XM2CMDPADCTRL */
+ 0x0800201c, /* EMC_XM2DQSPADCTRL2 */
+ 0x00000000, /* EMC_XM2DQPADCTRL2 */
+ 0x77ffc004, /* EMC_XM2CLKPADCTRL */
+ 0x01f1f008, /* EMC_XM2COMPPADCTRL */
+ 0x00000000, /* EMC_XM2VTTGENPADCTRL */
+ 0x00000007, /* EMC_XM2VTTGENPADCTRL2 */
+ 0x08000068, /* EMC_XM2QUSEPADCTRL */
+ 0x08000000, /* EMC_XM2DQSPADCTRL3 */
+ 0x00000802, /* EMC_CTT_TERM_CTRL */
+ 0x00000000, /* EMC_ZCAL_INTERVAL */
+ 0x00000013, /* EMC_ZCAL_WAIT_CNT */
+ 0x00090009, /* EMC_MRS_WAIT_CNT */
+ 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */
+ 0x00000000, /* EMC_CTT */
+ 0x00000000, /* EMC_CTT_DURATION */
+ 0x80000713, /* EMC_DYN_SELF_REF_CONTROL */
+ 0x00000003, /* MC_EMEM_ARB_CFG */
+ 0xc0000025, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RP */
+ 0x00000006, /* MC_EMEM_ARB_TIMING_RC */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_RAS */
+ 0x00000005, /* MC_EMEM_ARB_TIMING_FAW */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */
+ 0x00000004, /* MC_EMEM_ARB_TIMING_WAP2PRE */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_R2R */
+ 0x00000000, /* MC_EMEM_ARB_TIMING_W2W */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_R2W */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_W2R */
+ 0x02030001, /* MC_EMEM_ARB_DA_TURNS */
+ 0x00070506, /* MC_EMEM_ARB_DA_COVERS */
+ 0x71e40a07, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0xe0000000, /* EMC_FBIO_SPARE */
+ 0xff00ff00, /* EMC_CFG_RSV */
+ },
+ 0x00000013, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000001, /* EMC_CFG.PERIODIC_QRST */
+ 0x00000000, /* Mode Register 0 */
+ 0x00010042, /* Mode Register 1 */
+ 0x00020001, /* Mode Register 2 */
+ 0x00000001, /* EMC_CFG.DYN_SELF_REF */
+ },
+ {
+ 0x32, /* Rev 3.2 */
+ 533000, /* SDRAM frequency */
+ {
+ 0x0000001f, /* EMC_RC */
+ 0x00000045, /* EMC_RFC */
+ 0x00000016, /* EMC_RAS */
+ 0x00000009, /* EMC_RP */
+ 0x00000008, /* EMC_R2W */
+ 0x00000009, /* EMC_W2R */
+ 0x00000004, /* EMC_R2P */
+ 0x0000000d, /* EMC_W2P */
+ 0x00000009, /* EMC_RD_RCD */
+ 0x00000009, /* EMC_WR_RCD */
+ 0x00000005, /* EMC_RRD */
+ 0x00000003, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000004, /* EMC_WDV */
+ 0x00000009, /* EMC_QUSE */
+ 0x00000006, /* EMC_QRST */
+ 0x0000000d, /* EMC_QSAFE */
+ 0x00000010, /* EMC_RDV */
+ 0x000007e1, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x000001f8, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x00000003, /* EMC_PDEX2WR */
+ 0x00000003, /* EMC_PDEX2RD */
+ 0x00000009, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x00000001, /* EMC_AR2PDEN */
+ 0x0000000f, /* EMC_RW2PDEN */
+ 0x0000004b, /* EMC_TXSR */
+ 0x0000004b, /* EMC_TXSRDLL */
+ 0x00000008, /* EMC_TCKE */
+ 0x0000001b, /* EMC_TFAW */
+ 0x0000000c, /* EMC_TRPAB */
+ 0x00000001, /* EMC_TCLKSTABLE */
+ 0x00000002, /* EMC_TCLKSTOP */
+ 0x000008ab, /* EMC_TREFBW */
+ 0x00000000, /* EMC_QUSE_EXTRA */
+ 0x00000006, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00006282, /* EMC_FBIO_CFG5 */
+ 0xf0120091, /* EMC_CFG_DIG_DLL */
+ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */
+ 0x00000008, /* EMC_DLL_XFORM_DQS0 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS1 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS2 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS3 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS4 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS5 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS6 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS7 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE3 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE4 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE5 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE6 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE7 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */
+ 0x0000000c, /* EMC_DLL_XFORM_DQ0 */
+ 0x0000000c, /* EMC_DLL_XFORM_DQ1 */
+ 0x0000000c, /* EMC_DLL_XFORM_DQ2 */
+ 0x0000000c, /* EMC_DLL_XFORM_DQ3 */
+ 0x000a0220, /* EMC_XM2CMDPADCTRL */
+ 0x0800003d, /* EMC_XM2DQSPADCTRL2 */
+ 0x00000000, /* EMC_XM2DQPADCTRL2 */
+ 0x77ffc004, /* EMC_XM2CLKPADCTRL */
+ 0x01f1f408, /* EMC_XM2COMPPADCTRL */
+ 0x00000000, /* EMC_XM2VTTGENPADCTRL */
+ 0x00000007, /* EMC_XM2VTTGENPADCTRL2 */
+ 0x08000068, /* EMC_XM2QUSEPADCTRL */
+ 0x08000000, /* EMC_XM2DQSPADCTRL3 */
+ 0x00000802, /* EMC_CTT_TERM_CTRL */
+ 0x00064000, /* EMC_ZCAL_INTERVAL */
+ 0x000000c0, /* EMC_ZCAL_WAIT_CNT */
+ 0x000e000e, /* EMC_MRS_WAIT_CNT */
+ 0xa0f10202, /* EMC_AUTO_CAL_CONFIG */
+ 0x00000000, /* EMC_CTT */
+ 0x00000000, /* EMC_CTT_DURATION */
+ 0x800010dc, /* EMC_DYN_SELF_REF_CONTROL */
+ 0x00000008, /* MC_EMEM_ARB_CFG */
+ 0x80000060, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_RCD */
+ 0x00000004, /* MC_EMEM_ARB_TIMING_RP */
+ 0x00000010, /* MC_EMEM_ARB_TIMING_RC */
+ 0x0000000a, /* MC_EMEM_ARB_TIMING_RAS */
+ 0x0000000d, /* MC_EMEM_ARB_TIMING_FAW */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RRD */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_RAP2PRE */
+ 0x00000008, /* MC_EMEM_ARB_TIMING_WAP2PRE */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */
+ 0x00000000, /* MC_EMEM_ARB_TIMING_W2W */
+ 0x00000004, /* MC_EMEM_ARB_TIMING_R2W */
+ 0x00000005, /* MC_EMEM_ARB_TIMING_W2R */
+ 0x05040002, /* MC_EMEM_ARB_DA_TURNS */
+ 0x00110c10, /* MC_EMEM_ARB_DA_COVERS */
+ 0x70281811, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0xe0000000, /* EMC_FBIO_SPARE */
+ 0xff00ff88, /* EMC_CFG_RSV */
+ },
+ 0x00000030, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000001, /* EMC_CFG.PERIODIC_QRST */
+ 0x00000000, /* Mode Register 0 */
+ 0x000100c2, /* Mode Register 1 */
+ 0x00020006, /* Mode Register 2 */
+ 0x00000000, /* EMC_CFG.DYN_SELF_REF */
+ },
+};
+
int enterprise_emc_init(void)
{
struct board_info board_info;
@@ -754,8 +1477,12 @@ int enterprise_emc_init(void)
tegra_get_board_info(&board_info);
if (board_info.fab <= BOARD_FAB_A02)
- tegra_init_emc(enterprise_emc_tables_h5tc2g,
- ARRAY_SIZE(enterprise_emc_tables_h5tc2g));
+ tegra_init_emc(enterprise_emc_tables_kmmll0_a02,
+ ARRAY_SIZE(enterprise_emc_tables_kmmll0_a02));
+ else
+ tegra_init_emc(enterprise_emc_tables_kmkts0_a03,
+ ARRAY_SIZE(enterprise_emc_tables_kmkts0_a03));
+
return 0;
}
diff --git a/arch/arm/mach-tegra/board-enterprise-panel.c b/arch/arm/mach-tegra/board-enterprise-panel.c
index 8ac2e665addb..837635bf0731 100644
--- a/arch/arm/mach-tegra/board-enterprise-panel.c
+++ b/arch/arm/mach-tegra/board-enterprise-panel.c
@@ -26,9 +26,10 @@
#include <linux/platform_device.h>
#include <linux/earlysuspend.h>
#include <linux/tegra_pwm_bl.h>
+#include <linux/pwm_backlight.h>
#include <asm/atomic.h>
#include <linux/nvhost.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include <mach/irqs.h>
#include <mach/iomap.h>
#include <mach/dc.h>
@@ -39,6 +40,7 @@
#include "board-enterprise.h"
#include "devices.h"
#include "gpio-names.h"
+#include "tegra3_host1x_devices.h"
#define DC_CTRL_MODE TEGRA_DC_OUT_ONE_SHOT_MODE
@@ -61,6 +63,8 @@
#define enterprise_lcd_te TEGRA_GPIO_PJ1
+#define enterprise_bl_pwm TEGRA_GPIO_PH3
+
#ifdef CONFIG_TEGRA_DC
static struct regulator *enterprise_dsi_reg;
static bool dsi_regulator_status;
@@ -165,6 +169,17 @@ static int enterprise_backlight_notify(struct device *unused, int brightness)
static int enterprise_disp1_check_fb(struct device *dev, struct fb_info *info);
+#if IS_EXTERNAL_PWM
+static struct platform_pwm_backlight_data enterprise_disp1_backlight_data = {
+ .pwm_id = 3,
+ .max_brightness = 255,
+ .dft_brightness = 224,
+ .pwm_period_ns = 1000000,
+ .notify = enterprise_backlight_notify,
+ /* Only toggle backlight on fb blank notifications for disp1 */
+ .check_fb = enterprise_disp1_check_fb,
+};
+#else
/*
* In case which_pwm is TEGRA_PWM_PM0,
* gpio_conf_to_sfio should be TEGRA_GPIO_PW0: set LCD_CS1_N pin to SFIO
@@ -175,7 +190,6 @@ static struct platform_tegra_pwm_backlight_data enterprise_disp1_backlight_data
.which_dc = 0,
.which_pwm = TEGRA_PWM_PM1,
.gpio_conf_to_sfio = TEGRA_GPIO_PW1,
- .switch_to_sfio = &tegra_gpio_disable,
.max_brightness = 255,
.dft_brightness = 224,
.notify = enterprise_backlight_notify,
@@ -185,9 +199,15 @@ static struct platform_tegra_pwm_backlight_data enterprise_disp1_backlight_data
/* Only toggle backlight on fb blank notifications for disp1 */
.check_fb = enterprise_disp1_check_fb,
};
+#endif
+
static struct platform_device enterprise_disp1_backlight_device = {
+#if IS_EXTERNAL_PWM
+ .name = "pwm-backlight",
+#else
.name = "tegra-pwm-bl",
+#endif
.id = -1,
.dev = {
.platform_data = &enterprise_disp1_backlight_data,
@@ -510,8 +530,11 @@ static int enterprise_dsi_panel_enable(void)
if (ret)
return ret;
-#if DSI_PANEL_RESET
+#if IS_EXTERNAL_PWM
+ tegra_gpio_disable(enterprise_bl_pwm);
+#endif
+#if DSI_PANEL_RESET
if (board_info.fab >= BOARD_FAB_A03) {
if (enterprise_lcd_reg == NULL) {
enterprise_lcd_reg = regulator_get(NULL, "lcd_vddio_en");
@@ -541,7 +564,6 @@ static int enterprise_dsi_panel_enable(void)
gpio_free(enterprise_dsi_panel_reset);
return ret;
}
- tegra_gpio_enable(enterprise_dsi_panel_reset);
gpio_set_value(enterprise_dsi_panel_reset, 0);
udelay(2000);
@@ -560,7 +582,6 @@ static int enterprise_dsi_panel_disable(void)
#if DSI_PANEL_RESET
if (kernel_1st_panel_init != true) {
- tegra_gpio_disable(enterprise_dsi_panel_reset);
gpio_free(enterprise_dsi_panel_reset);
} else
kernel_1st_panel_init = false;
@@ -796,7 +817,11 @@ static struct platform_device *enterprise_gfx_devices[] __initdata = {
#if defined(CONFIG_TEGRA_NVMAP)
&enterprise_nvmap_device,
#endif
+#if IS_EXTERNAL_PWM
+ &tegra_pwfm3_device,
+#else
&tegra_pwfm0_device,
+#endif
};
static struct platform_device *enterprise_bl_devices[] = {
@@ -816,17 +841,10 @@ static void enterprise_panel_early_suspend(struct early_suspend *h)
fb_blank(registered_fb[0], FB_BLANK_POWERDOWN);
if (num_registered_fb > 1)
fb_blank(registered_fb[1], FB_BLANK_NORMAL);
-#ifdef CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND
- cpufreq_save_default_governor();
- cpufreq_set_conservative_governor();
- cpufreq_set_conservative_governor_param("up_threshold",
- SET_CONSERVATIVE_GOVERNOR_UP_THRESHOLD);
-
- cpufreq_set_conservative_governor_param("down_threshold",
- SET_CONSERVATIVE_GOVERNOR_DOWN_THRESHOLD);
- cpufreq_set_conservative_governor_param("freq_step",
- SET_CONSERVATIVE_GOVERNOR_FREQ_STEP);
+#ifdef CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND
+ cpufreq_store_default_gov();
+ cpufreq_change_gov(cpufreq_conservative_gov);
#endif
}
@@ -835,7 +853,7 @@ static void enterprise_panel_late_resume(struct early_suspend *h)
unsigned i;
#ifdef CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND
- cpufreq_restore_default_governor();
+ cpufreq_restore_default_gov();
#endif
for (i = 0; i < num_registered_fb; i++)
fb_blank(registered_fb[i], FB_BLANK_UNBLANK);
@@ -854,7 +872,9 @@ int __init enterprise_panel_init(void)
BUILD_BUG_ON(ARRAY_SIZE(enterprise_bl_output_measured_a02) != 256);
if (board_info.fab >= BOARD_FAB_A03) {
+#if !(IS_EXTERNAL_PWM)
enterprise_disp1_backlight_data.clk_div = 0x1D;
+#endif
bl_output = enterprise_bl_output_measured_a03;
} else
bl_output = enterprise_bl_output_measured_a02;
@@ -867,22 +887,18 @@ int __init enterprise_panel_init(void)
enterprise_carveouts[1].size = tegra_carveout_size;
#endif
- tegra_gpio_enable(enterprise_hdmi_hpd);
gpio_request(enterprise_hdmi_hpd, "hdmi_hpd");
gpio_direction_input(enterprise_hdmi_hpd);
- tegra_gpio_enable(enterprise_lcd_2d_3d);
gpio_request(enterprise_lcd_2d_3d, "lcd_2d_3d");
gpio_direction_output(enterprise_lcd_2d_3d, 0);
enterprise_stereo_set_mode(enterprise_stereo.mode_2d_3d);
- tegra_gpio_enable(enterprise_lcd_swp_pl);
gpio_request(enterprise_lcd_swp_pl, "lcd_swp_pl");
gpio_direction_output(enterprise_lcd_swp_pl, 0);
enterprise_stereo_set_orientation(enterprise_stereo.orientation);
#if !(DC_CTRL_MODE & TEGRA_DC_OUT_ONE_SHOT_MODE)
- tegra_gpio_enable(enterprise_lcd_te);
gpio_request(enterprise_lcd_swp_pl, "lcd_te");
gpio_direction_input(enterprise_lcd_te);
#endif
@@ -895,7 +911,7 @@ int __init enterprise_panel_init(void)
#endif
#ifdef CONFIG_TEGRA_GRHOST
- err = nvhost_device_register(&tegra_grhost_device);
+ err = tegra3_register_host1x_devices();
if (err)
return err;
#endif
diff --git a/arch/arm/mach-tegra/board-enterprise-pinmux.c b/arch/arm/mach-tegra/board-enterprise-pinmux.c
index 8d18e3296af3..721eb0d27576 100644
--- a/arch/arm/mach-tegra/board-enterprise-pinmux.c
+++ b/arch/arm/mach-tegra/board-enterprise-pinmux.c
@@ -215,7 +215,7 @@ static __initdata struct tegra_pingroup_config enterprise_pinmux_common[] = {
DEFAULT_PINMUX(LCD_D5, DISPLAYA, NORMAL, NORMAL, INPUT),
DEFAULT_PINMUX(LCD_D6, RSVD1, NORMAL, NORMAL, INPUT),
DEFAULT_PINMUX(LCD_D7, RSVD1, NORMAL, NORMAL, OUTPUT),
- DEFAULT_PINMUX(LCD_D8, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D8, DISPLAYA, NORMAL, TRISTATE, INPUT),
DEFAULT_PINMUX(LCD_D9, DISPLAYA, NORMAL, NORMAL, INPUT),
DEFAULT_PINMUX(LCD_D11, DISPLAYA, NORMAL, NORMAL, INPUT),
DEFAULT_PINMUX(LCD_D12, DISPLAYA, NORMAL, NORMAL, INPUT),
@@ -265,6 +265,9 @@ static __initdata struct tegra_pingroup_config enterprise_pinmux_common[] = {
DEFAULT_PINMUX(GMI_AD8, PWM0, NORMAL, NORMAL, OUTPUT),
DEFAULT_PINMUX(GMI_AD9, NAND, NORMAL, NORMAL, OUTPUT),
DEFAULT_PINMUX(GMI_AD10, NAND, NORMAL, NORMAL, OUTPUT),
+#if IS_EXTERNAL_PWM
+ DEFAULT_PINMUX(GMI_AD11, PWM3, NORMAL, NORMAL, OUTPUT),
+#endif
DEFAULT_PINMUX(GMI_A16, UARTD, NORMAL, NORMAL, OUTPUT),
DEFAULT_PINMUX(GMI_A17, UARTD, NORMAL, NORMAL, INPUT),
DEFAULT_PINMUX(GMI_A18, UARTD, NORMAL, NORMAL, INPUT),
@@ -379,7 +382,9 @@ static __initdata struct tegra_pingroup_config enterprise_unused_pinmux_common[]
DEFAULT_PINMUX(GMI_AD5, GMI, NORMAL, TRISTATE, OUTPUT),
DEFAULT_PINMUX(GMI_AD6, GMI, NORMAL, TRISTATE, OUTPUT),
DEFAULT_PINMUX(GMI_AD7, GMI, NORMAL, TRISTATE, OUTPUT),
+#if !(IS_EXTERNAL_PWM)
DEFAULT_PINMUX(GMI_AD11, GMI, PULL_DOWN, TRISTATE, OUTPUT),
+#endif
DEFAULT_PINMUX(GMI_CS0_N, GMI, PULL_DOWN, TRISTATE, OUTPUT),
DEFAULT_PINMUX(GMI_CS2_N, GMI, PULL_DOWN, TRISTATE, OUTPUT),
DEFAULT_PINMUX(GMI_CS3_N, GMI, PULL_DOWN, TRISTATE, OUTPUT),
@@ -460,7 +465,9 @@ static __initdata struct pin_info_low_power_mode enterprise_unused_gpio_pins_com
PIN_GPIO_LPM("GMI_AD5", TEGRA_GPIO_PG5, 0, 0),
PIN_GPIO_LPM("GMI_AD6", TEGRA_GPIO_PG6, 0, 0),
PIN_GPIO_LPM("GMI_AD7", TEGRA_GPIO_PG7, 0, 0),
+#if !(IS_EXTERNAL_PWM)
PIN_GPIO_LPM("GMI_AD11", TEGRA_GPIO_PH3, 0, 0),
+#endif
PIN_GPIO_LPM("GMI_CS0_N", TEGRA_GPIO_PJ0, 0, 0),
PIN_GPIO_LPM("GMI_CS2_N", TEGRA_GPIO_PK3, 0, 0),
PIN_GPIO_LPM("GMI_CS3_N", TEGRA_GPIO_PK4, 0, 0),
@@ -534,7 +541,6 @@ static void enterprise_set_unused_pin_gpio(struct pin_info_low_power_mode *lpm_p
gpio_free(pin_info->gpio_nr);
continue;
}
- tegra_gpio_enable(pin_info->gpio_nr);
}
}
diff --git a/arch/arm/mach-tegra/board-enterprise-power.c b/arch/arm/mach-tegra/board-enterprise-power.c
index c17c3eaf5cfa..bbe39ec4ad3e 100644
--- a/arch/arm/mach-tegra/board-enterprise-power.c
+++ b/arch/arm/mach-tegra/board-enterprise-power.c
@@ -44,7 +44,6 @@
#include "board.h"
#include "board-enterprise.h"
#include "pm.h"
-#include "wakeups-t3.h"
#include "tegra3_tsensor.h"
#define PMC_CTRL 0x0
@@ -141,9 +140,10 @@ static struct regulator_consumer_supply tps80031_smps4_supply_a03[] = {
REGULATOR_SUPPLY("vddf_core_emmc", NULL),
};
-static struct regulator_consumer_supply tps80031_vana_supply_common[] = {
+static struct regulator_consumer_supply tps80031_vana_supply_a02[] = {
REGULATOR_SUPPLY("unused_vana", NULL),
};
+#define tps80031_vana_supply_a03 tps80031_vana_supply_a02
static struct regulator_consumer_supply tps80031_ldo1_supply_a02[] = {
REGULATOR_SUPPLY("avdd_dsi_csi", NULL),
@@ -269,23 +269,24 @@ TPS_PDATA_INIT(smps1, common, 600, 2100, 0, 0, 0, 0, -1, 0, 0, 0, PWR_REQ_INPUT_
TPS_PDATA_INIT(smps2, common, 600, 2100, 0, 0, 0, 0, -1, 0, 0, 0, PWR_REQ_INPUT_PREQ1, 0);
TPS_PDATA_INIT(smps3, common, 600, 2100, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0);
TPS_PDATA_INIT(smps4, a02, 600, 2100, 0, 0, 0, 0, -1, 0, 0, 0, PWR_REQ_INPUT_PREQ1, 0);
-TPS_PDATA_INIT(smps4, a03, 600, 2100, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0);
+TPS_PDATA_INIT(smps4, a03, 600, 2100, 0, 0, 0, 0, -1, 0, 0, 0, PWR_REQ_INPUT_PREQ1, 0);
TPS_PDATA_INIT(ldo1, a02, 1000, 3300, tps80031_rails(VIO), 0, 0, 0, -1, 0, 0, 0, 0, 0);
TPS_PDATA_INIT(ldo1, a03, 1000, 3300, tps80031_rails(VIO), 0, 0, 0, -1, 0, 0, 0, PWR_REQ_INPUT_PREQ1, 0);
TPS_PDATA_INIT(ldo2, common, 1000, 3300, 0, 1, 1, 1, 1000, 1, 1, 0, 0, 0);
TPS_PDATA_INIT(ldo3, common, 1000, 3300, tps80031_rails(VIO), 0, 0, 0, -1, 0, 0, 0, PWR_OFF_ON_SLEEP, 0);
TPS_PDATA_INIT(ldo4, a02, 1000, 3300, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0);
-TPS_PDATA_INIT(ldo4, a03, 1000, 3300, tps80031_rails(VIO), 0, 0, 0, -1, 0, 0, 0, 0, 0);
+TPS_PDATA_INIT(ldo4, a03, 1000, 3300, tps80031_rails(VIO), 0, 0, 0, -1, 0, 0, 0, PWR_REQ_INPUT_PREQ1, 0);
TPS_PDATA_INIT(ldo5, common, 1000, 3300, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0);
TPS_PDATA_INIT(ldo6, a02, 1000, 3300, 0, 0, 0, 0, -1, 0, 0, 0, PWR_REQ_INPUT_PREQ1, 0);
TPS_PDATA_INIT(ldo6, a03, 1000, 3300, 0, 0, 0, 0, -1, 0, 0, 0, PWR_REQ_INPUT_PREQ1, 0);
TPS_PDATA_INIT(ldo7, a02, 1000, 3300, tps80031_rails(VIO), 0, 0, 0, -1, 0, 0, 0, PWR_REQ_INPUT_PREQ1, 0);
-TPS_PDATA_INIT(ldo7, a03, 1000, 3300, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0);
+TPS_PDATA_INIT(ldo7, a03, 1000, 3300, 0, 0, 0, 0, -1, 0, 0, 0, PWR_REQ_INPUT_PREQ1, 0);
TPS_PDATA_INIT(ldoln, a02, 1000, 3300, tps80031_rails(SMPS3), 0, 0, 0, -1, 0, 0, 0, PWR_REQ_INPUT_PREQ1, 0);
TPS_PDATA_INIT(ldoln, a03, 1000, 3300, tps80031_rails(VIO), 0, 0, 0, -1, 0, 0, 0, PWR_REQ_INPUT_PREQ1, 0);
TPS_PDATA_INIT(ldousb, a02, 1000, 3300, 0, 0, 0, 0, -1, 0, 0, USBLDO_INPUT_VSYS, PWR_OFF_ON_SLEEP, 0);
-TPS_PDATA_INIT(ldousb, a03, 1000, 3300, 0, 0, 0, 0, -1, 0, 0, USBLDO_INPUT_VSYS, PWR_OFF_ON_SLEEP, 0);
-TPS_PDATA_INIT(vana, common, 1000, 3300, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0);
+TPS_PDATA_INIT(ldousb, a03, 1000, 3300, 0, 0, 0, 0, -1, 0, 0, USBLDO_INPUT_VSYS, PWR_REQ_INPUT_PREQ1, 0);
+TPS_PDATA_INIT(vana, a02, 1000, 3300, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0);
+TPS_PDATA_INIT(vana, a03, 1000, 3300, 0, 0, 0, 0, -1, 0, 1, 0, PWR_OFF_ON_SLEEP, 0);
TPS_PDATA_INIT(vbus, common, 0, 5000, 0, 0, 0, 0, -1, 0, 0, (VBUS_SW_ONLY | VBUS_DISCHRG_EN_PDN), 0, 100000);
static struct tps80031_rtc_platform_data rtc_data = {
@@ -298,6 +299,7 @@ static struct tps80031_rtc_platform_data rtc_data = {
.tm_min = 2,
.tm_sec = 3,
},
+ .msecure_gpio = TEGRA_GPIO_PF7,
};
int battery_charger_init(void *board_data)
@@ -309,7 +311,6 @@ int battery_charger_init(void *board_data)
" charger fails\n", __func__);
}
gpio_direction_output(TEGRA_GPIO_PF6, 1);
- tegra_gpio_enable(TEGRA_GPIO_PF6);
return 0;
}
@@ -362,7 +363,6 @@ static struct tps80031_bg_platform_data battery_gauge_data = {
TPS_REG(SMPS1, smps1, common), \
TPS_REG(SMPS2, smps2, common), \
TPS_REG(SMPS3, smps3, common), \
- TPS_REG(VANA, vana, common), \
TPS_REG(LDO2, ldo2, common), \
TPS_REG(LDO3, ldo3, common), \
TPS_REG(LDO5, ldo5, common), \
@@ -374,8 +374,8 @@ static struct tps80031_bg_platform_data battery_gauge_data = {
static struct tps80031_subdev_info tps80031_devs_a02[] = {
- TPS80031_DEVS_COMMON,
TPS_REG(VIO, vio, a02),
+ TPS80031_DEVS_COMMON,
TPS_REG(SMPS4, smps4, a02),
TPS_REG(LDO1, ldo1, a02),
TPS_REG(LDO4, ldo4, a02),
@@ -383,12 +383,13 @@ static struct tps80031_subdev_info tps80031_devs_a02[] = {
TPS_REG(LDO7, ldo7, a02),
TPS_REG(LDOLN, ldoln, a02),
TPS_REG(LDOUSB, ldousb, a02),
+ TPS_REG(VANA, vana, a02),
};
static struct tps80031_subdev_info tps80031_devs_a03[] = {
- TPS80031_DEVS_COMMON,
TPS_REG(VIO, vio, a03),
+ TPS80031_DEVS_COMMON,
TPS_REG(SMPS4, smps4, a03),
TPS_REG(LDO1, ldo1, a03),
TPS_REG(LDO4, ldo4, a03),
@@ -396,10 +397,11 @@ static struct tps80031_subdev_info tps80031_devs_a03[] = {
TPS_REG(LDO7, ldo7, a03),
TPS_REG(LDOLN, ldoln, a03),
TPS_REG(LDOUSB, ldousb, a03),
+ TPS_REG(VANA, vana, a03),
};
-struct tps80031_clk32k_init_data clk32k_idata[] = {
+static struct tps80031_clk32k_init_data clk32k_idata[] = {
{
.clk32k_nr = TPS80031_CLOCK32K_G,
.enable = true,
@@ -410,6 +412,23 @@ struct tps80031_clk32k_init_data clk32k_idata[] = {
.enable = true,
.ext_ctrl_flag = 0,
},
+
+
+};
+
+static struct tps80031_gpio_init_data gpio_idata_a03[] = {
+ {
+ .gpio_nr = TPS80031_GPIO_REGEN1,
+ .ext_ctrl_flag = PWR_REQ_INPUT_PREQ1,
+ },
+ {
+ .gpio_nr = TPS80031_GPIO_REGEN2,
+ .ext_ctrl_flag = PWR_REQ_INPUT_PREQ1,
+ },
+ {
+ .gpio_nr = TPS80031_GPIO_SYSEN,
+ .ext_ctrl_flag = PWR_REQ_INPUT_PREQ1,
+ },
};
static struct tps80031_pupd_init_data pupd_idata[] = {
@@ -463,7 +482,7 @@ static struct regulator_consumer_supply fixed_reg_vdd_fuse_en_supply[] = {
static struct regulator_consumer_supply gpio_reg_sdmmc3_vdd_sel_supply[] = {
REGULATOR_SUPPLY("vddio_sdmmc3_2v85_1v8", NULL),
REGULATOR_SUPPLY("sdmmc3_compu_pu", NULL),
- REGULATOR_SUPPLY("vddio_sdmmc3", NULL),
+ REGULATOR_SUPPLY("vddio_sdmmc", "sdhci-tegra.2"),
REGULATOR_SUPPLY("vsys_3v7", NULL),
};
@@ -644,8 +663,12 @@ FIXED_REG(8, lcd_1v8_en, NULL,
ADD_FIXED_REG(cam_ldo_1v8_en)
static struct platform_device *fixed_regs_devices_a02[] = {
- FIXED_REGS_COMMON,
- ADD_FIXED_REG(pmu_3v3_en),
+ ADD_FIXED_REG(pmu_5v15_en), \
+ ADD_FIXED_REG(pmu_3v3_en), \
+ ADD_FIXED_REG(pmu_hdmi_5v0_en), \
+ ADD_FIXED_REG(vdd_fuse_en), \
+ ADD_FIXED_REG(cam_ldo_2v8_en), \
+ ADD_FIXED_REG(cam_ldo_1v8_en)
};
static struct platform_device *fixed_regs_devices_a03[] = {
@@ -661,7 +684,6 @@ static struct platform_device *gpio_regs_devices[] = {
static int __init enterprise_fixed_regulator_init(void)
{
- int i;
struct board_info board_info;
struct platform_device **fixed_regs_devices;
int nfixreg_devs;
@@ -676,27 +698,11 @@ static int __init enterprise_fixed_regulator_init(void)
nfixreg_devs = ARRAY_SIZE(fixed_regs_devices_a03);
}
- for (i = 0; i < nfixreg_devs; ++i) {
- struct fixed_voltage_config *fixed_reg_pdata =
- fixed_regs_devices[i]->dev.platform_data;
- if (fixed_reg_pdata->gpio < TEGRA_NR_GPIOS)
- tegra_gpio_enable(fixed_reg_pdata->gpio);
- }
return platform_add_devices(fixed_regs_devices, nfixreg_devs);
}
static int __init enterprise_gpio_regulator_init(void)
{
- int i, j;
-
- for (i = 0; i < ARRAY_SIZE(gpio_regs_devices); ++i) {
- struct gpio_regulator_config *gpio_reg_pdata =
- gpio_regs_devices[i]->dev.platform_data;
- for (j = 0; j < gpio_reg_pdata->nr_gpios; ++j) {
- if (gpio_reg_pdata->gpios[j].gpio < TEGRA_NR_GPIOS)
- tegra_gpio_enable(gpio_reg_pdata->gpios[j].gpio);
- }
- }
return platform_add_devices(gpio_regs_devices,
ARRAY_SIZE(gpio_regs_devices));
}
@@ -742,6 +748,8 @@ int __init enterprise_regulator_init(void)
battery_gauge_data.battery_present = 0;
}
+ tegra_gpio_enable(TEGRA_GPIO_PF7);
+
if (board_info.fab < BOARD_FAB_A03) {
tps_platform.num_subdevs = ARRAY_SIZE(tps80031_devs_a02);
tps_platform.subdevs = tps80031_devs_a02;
@@ -750,6 +758,8 @@ int __init enterprise_regulator_init(void)
tps_platform.subdevs = tps80031_devs_a03;
tps_platform.pupd_init_data = pupd_idata;
tps_platform.pupd_init_data_size = ARRAY_SIZE(pupd_idata);
+ tps_platform.gpio_init_data = gpio_idata_a03;
+ tps_platform.gpio_init_data_size = ARRAY_SIZE(gpio_idata_a03);
}
i2c_register_board_info(4, enterprise_regulators, 1);
@@ -835,8 +845,6 @@ void __init enterprise_bpc_mgmt_init(void)
{
int int_gpio = TEGRA_GPIO_TO_IRQ(TEGRA_BPC_TRIGGER);
- tegra_gpio_enable(TEGRA_BPC_TRIGGER);
-
#ifdef CONFIG_SMP
cpumask_setall(&(bpc_mgmt_platform_data.affinity_mask));
irq_set_affinity_hint(int_gpio,
diff --git a/arch/arm/mach-tegra/board-enterprise-sdhci.c b/arch/arm/mach-tegra/board-enterprise-sdhci.c
index 4102ef464d1e..7a5632601fe6 100644
--- a/arch/arm/mach-tegra/board-enterprise-sdhci.c
+++ b/arch/arm/mach-tegra/board-enterprise-sdhci.c
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/board-enterprise-sdhci.c
*
- * Copyright (C) 2011 NVIDIA Corporation.
+ * Copyright (C) 2011-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
@@ -143,13 +143,17 @@ static struct tegra_sdhci_platform_data tegra_sdhci_platform_data0 = {
.cd_gpio = -1,
.wp_gpio = -1,
.power_gpio = -1,
+ .tap_delay = 0x0F,
.max_clk_limit = 45000000,
+ .ddr_clk_limit = 41000000,
};
static struct tegra_sdhci_platform_data tegra_sdhci_platform_data2 = {
.cd_gpio = -1,
.wp_gpio = -1,
.power_gpio = -1,
+ .tap_delay = 0x0F,
+ .ddr_clk_limit = 41000000,
};
static struct tegra_sdhci_platform_data tegra_sdhci_platform_data3 = {
@@ -158,6 +162,7 @@ static struct tegra_sdhci_platform_data tegra_sdhci_platform_data3 = {
.power_gpio = -1,
.is_8bit = 1,
.tap_delay = 0x0F,
+ .ddr_clk_limit = 41000000,
.mmc_data = {
.built_in = 1,
}
@@ -259,10 +264,6 @@ static int __init enterprise_wifi_init(void)
if (rc)
pr_err("WLAN_WOW gpio request failed:%d\n", rc);
- tegra_gpio_enable(ENTERPRISE_WLAN_PWR);
- tegra_gpio_enable(ENTERPRISE_WLAN_RST);
- tegra_gpio_enable(ENTERPRISE_WLAN_WOW);
-
rc = gpio_direction_output(ENTERPRISE_WLAN_PWR, 0);
if (rc)
pr_err("WLAN_PWR gpio direction configuration failed:%d\n", rc);
@@ -281,7 +282,6 @@ int __init enterprise_sdhci_init(void)
{
platform_device_register(&tegra_sdhci_device3);
- tegra_gpio_enable(ENTERPRISE_SD_CD);
tegra_sdhci_platform_data2.cd_gpio = ENTERPRISE_SD_CD;
platform_device_register(&tegra_sdhci_device2);
diff --git a/arch/arm/mach-tegra/board-enterprise-sensors.c b/arch/arm/mach-tegra/board-enterprise-sensors.c
index f775c2bd3b3e..aab409b89ea9 100644
--- a/arch/arm/mach-tegra/board-enterprise-sensors.c
+++ b/arch/arm/mach-tegra/board-enterprise-sensors.c
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/board-enterprise-sensors.c
*
- * Copyright (c) 2011, NVIDIA CORPORATION, All rights reserved.
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION, All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -101,6 +101,7 @@ static void nct1008_probe_callback(struct nct1008_data *data)
thermal_device->name = "nct1008";
thermal_device->data = data;
+ thermal_device->id = THERMAL_DEVICE_ID_NCT_EXT;
thermal_device->offset = TDIODE_OFFSET;
thermal_device->get_temp = nct_get_temp;
thermal_device->get_temp_low = nct_get_temp_low;
@@ -108,7 +109,7 @@ static void nct1008_probe_callback(struct nct1008_data *data)
thermal_device->set_alert = nct_set_alert;
thermal_device->set_shutdown_temp = nct_set_shutdown_temp;
- tegra_thermal_set_device(thermal_device);
+ tegra_thermal_device_register(thermal_device);
}
static struct nct1008_platform_data enterprise_nct1008_pdata = {
@@ -131,7 +132,6 @@ static void enterprise_nct1008_init(void)
{
int ret;
- tegra_gpio_enable(TEGRA_GPIO_PH7);
ret = gpio_request(TEGRA_GPIO_PH7, "temp_alert");
if (ret < 0) {
pr_err("%s: gpio_request failed %d\n", __func__, ret);
@@ -213,7 +213,6 @@ static void mpuirq_init(void)
#if (MPU_GYRO_TYPE == MPU_TYPE_MPU3050)
#if MPU_ACCEL_IRQ_GPIO
/* ACCEL-IRQ assignment */
- tegra_gpio_enable(MPU_ACCEL_IRQ_GPIO);
ret = gpio_request(MPU_ACCEL_IRQ_GPIO, MPU_ACCEL_NAME);
if (ret < 0) {
pr_err("%s: gpio_request failed %d\n", __func__, ret);
@@ -230,7 +229,6 @@ static void mpuirq_init(void)
#endif
/* MPU-IRQ assignment */
- tegra_gpio_enable(MPU_GYRO_IRQ_GPIO);
ret = gpio_request(MPU_GYRO_IRQ_GPIO, MPU_GYRO_NAME);
if (ret < 0) {
pr_err("%s: gpio_request failed %d\n", __func__, ret);
@@ -589,7 +587,6 @@ static int enterprise_cam_init(void)
gpio_direction_output(enterprise_cam_gpio_data[i].gpio,
enterprise_cam_gpio_data[i].value);
gpio_export(enterprise_cam_gpio_data[i].gpio, false);
- tegra_gpio_enable(enterprise_cam_gpio_data[i].gpio);
}
tegra_get_board_info(&bi);
diff --git a/arch/arm/mach-tegra/board-enterprise.c b/arch/arm/mach-tegra/board-enterprise.c
index fb2b89bcba60..9c8890ed96cf 100644
--- a/arch/arm/mach-tegra/board-enterprise.c
+++ b/arch/arm/mach-tegra/board-enterprise.c
@@ -37,6 +37,7 @@
#include <linux/fsl_devices.h>
#include <linux/i2c/atmel_mxt_ts.h>
#include <linux/memblock.h>
+#include <linux/rfkill-gpio.h>
#include <linux/nfc/pn544.h>
#include <sound/max98088.h>
@@ -54,6 +55,7 @@
#include <mach/tegra_asoc_pdata.h>
#include <mach/thermal.h>
#include <mach/tegra-bb-power.h>
+#include <mach/tegra_fiq_debugger.h>
#include "board.h"
#include "clock.h"
#include "board-enterprise.h"
@@ -63,75 +65,77 @@
#include "fuse.h"
#include "pm.h"
+static struct balanced_throttle throttle_list[] = {
+ {
+ .id = BALANCED_THROTTLE_ID_TJ,
+ .throt_tab_size = 10,
+ .throt_tab = {
+ { 0, 1000 },
+ { 640000, 1000 },
+ { 640000, 1000 },
+ { 640000, 1000 },
+ { 640000, 1000 },
+ { 640000, 1000 },
+ { 760000, 1000 },
+ { 760000, 1050 },
+ {1000000, 1050 },
+ {1000000, 1100 },
+ },
+ },
+#ifdef CONFIG_TEGRA_SKIN_THROTTLE
+ {
+ .id = BALANCED_THROTTLE_ID_SKIN,
+ .throt_tab_size = 6,
+ .throt_tab = {
+ { 640000, 1200 },
+ { 640000, 1200 },
+ { 760000, 1200 },
+ { 760000, 1200 },
+ {1000000, 1200 },
+ {1000000, 1200 },
+ },
+ },
+#endif
+};
+
/* All units are in millicelsius */
static struct tegra_thermal_data thermal_data = {
- .temp_throttle = 85000,
+ .shutdown_device_id = THERMAL_DEVICE_ID_NCT_EXT,
.temp_shutdown = 90000,
- .temp_offset = TDIODE_OFFSET, /* temps based on tdiode */
+#if defined(CONFIG_TEGRA_EDP_LIMITS) || defined(CONFIG_TEGRA_THERMAL_THROTTLE)
+ .throttle_edp_device_id = THERMAL_DEVICE_ID_NCT_EXT,
+#endif
#ifdef CONFIG_TEGRA_EDP_LIMITS
.edp_offset = TDIODE_OFFSET, /* edp based on tdiode */
.hysteresis_edp = 3000,
#endif
-#ifdef CONFIG_TEGRA_THERMAL_SYSFS
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
+ .temp_throttle = 85000,
.tc1 = 0,
.tc2 = 1,
.passive_delay = 2000,
-#else
- .hysteresis_throttle = 1000,
+#endif
+#ifdef CONFIG_TEGRA_SKIN_THROTTLE
+ .skin_device_id = THERMAL_DEVICE_ID_SKIN,
+ .temp_throttle_skin = 43000,
#endif
};
-/* !!!TODO: Change for enterprise (Taken from Cardhu) */
-static struct tegra_utmip_config utmi_phy_config[] = {
- [0] = {
- .hssync_start_delay = 0,
- .idle_wait_delay = 17,
- .elastic_limit = 16,
- .term_range_adj = 6,
- .xcvr_setup = 15,
- .xcvr_setup_offset = 0,
- .xcvr_use_fuses = 1,
- .xcvr_lsfslew = 2,
- .xcvr_lsrslew = 2,
- },
- [1] = {
- .hssync_start_delay = 0,
- .idle_wait_delay = 17,
- .elastic_limit = 16,
- .term_range_adj = 6,
- .xcvr_setup = 15,
- .xcvr_setup_offset = 0,
- .xcvr_use_fuses = 1,
- .xcvr_lsfslew = 2,
- .xcvr_lsrslew = 2,
- },
- [2] = {
- .hssync_start_delay = 0,
- .idle_wait_delay = 17,
- .elastic_limit = 16,
- .term_range_adj = 6,
- .xcvr_setup = 8,
- .xcvr_setup_offset = 0,
- .xcvr_use_fuses = 1,
- .xcvr_lsfslew = 2,
- .xcvr_lsrslew = 2,
- },
-};
-
-static struct resource enterprise_bcm4329_rfkill_resources[] = {
+static struct rfkill_gpio_platform_data enterprise_bt_rfkill_pdata[] = {
{
- .name = "bcm4329_nshutdown_gpio",
- .start = TEGRA_GPIO_PE6,
- .end = TEGRA_GPIO_PE6,
- .flags = IORESOURCE_IO,
+ .name = "bt_rfkill",
+ .shutdown_gpio = TEGRA_GPIO_PE6,
+ .reset_gpio = TEGRA_GPIO_INVALID,
+ .type = RFKILL_TYPE_BLUETOOTH,
},
};
-static struct platform_device enterprise_bcm4329_rfkill_device = {
- .name = "bcm4329_rfkill",
+static struct platform_device enterprise_bt_rfkill_device = {
+ .name = "rfkill_gpio",
.id = -1,
- .num_resources = ARRAY_SIZE(enterprise_bcm4329_rfkill_resources),
- .resource = enterprise_bcm4329_rfkill_resources,
+ .dev = {
+ .platform_data = &enterprise_bt_rfkill_pdata,
+ },
};
static struct resource enterprise_bluesleep_resources[] = {
@@ -165,8 +169,6 @@ static struct platform_device enterprise_bluesleep_device = {
static void __init enterprise_setup_bluesleep(void)
{
platform_device_register(&enterprise_bluesleep_device);
- tegra_gpio_enable(TEGRA_GPIO_PS2);
- tegra_gpio_enable(TEGRA_GPIO_PE7);
return;
}
@@ -175,7 +177,7 @@ static __initdata struct tegra_clk_init_table enterprise_clk_init_table[] = {
{ "pll_m", NULL, 0, false},
{ "hda", "pll_p", 108000000, false},
{ "hda2codec_2x","pll_p", 48000000, false},
- { "pwm", "clk_32k", 32768, false},
+ { "pwm", "pll_p", 3187500, false},
{ "blink", "clk_32k", 32768, true},
{ "i2s0", "pll_a_out0", 0, false},
{ "i2s1", "pll_a_out0", 0, false},
@@ -207,7 +209,7 @@ static struct tegra_i2c_platform_data enterprise_i2c1_platform_data = {
static struct tegra_i2c_platform_data enterprise_i2c2_platform_data = {
.adapter_nr = 1,
.bus_count = 1,
- .bus_clk_rate = { 100000, 0 },
+ .bus_clk_rate = { 400000, 0 },
.is_clkon_always = true,
.scl_gpio = {TEGRA_GPIO_PT5, 0},
.sda_gpio = {TEGRA_GPIO_PT6, 0},
@@ -235,7 +237,7 @@ static struct tegra_i2c_platform_data enterprise_i2c4_platform_data = {
static struct tegra_i2c_platform_data enterprise_i2c5_platform_data = {
.adapter_nr = 4,
.bus_count = 1,
- .bus_clk_rate = { 100000, 0 },
+ .bus_clk_rate = { 400000, 0 },
.scl_gpio = {TEGRA_GPIO_PZ6, 0},
.sda_gpio = {TEGRA_GPIO_PZ7, 0},
.arb_recovery = arb_lost_recovery,
@@ -552,12 +554,14 @@ static struct platform_device *enterprise_devices[] __initdata = {
#if defined(CONFIG_TEGRA_IOVMM_SMMU) || defined(CONFIG_TEGRA_IOMMU_SMMU)
&tegra_smmu_device,
#endif
- &tegra_wdt_device,
+ &tegra_wdt0_device,
+ &tegra_wdt1_device,
+ &tegra_wdt2_device,
#if defined(CONFIG_TEGRA_AVP)
&tegra_avp_device,
#endif
&tegra_camera,
- &enterprise_bcm4329_rfkill_device,
+ &enterprise_bt_rfkill_device,
&tegra_spi_device4,
&tegra_hda_device,
#if defined(CONFIG_CRYPTO_DEV_TEGRA_SE)
@@ -638,9 +642,6 @@ static struct i2c_board_info __initdata atmel_i2c_info[] = {
static int __init enterprise_touch_init(void)
{
- tegra_gpio_enable(TEGRA_GPIO_PH6);
- tegra_gpio_enable(TEGRA_GPIO_PF5);
-
gpio_request(TEGRA_GPIO_PH6, "atmel-irq");
gpio_direction_input(TEGRA_GPIO_PH6);
@@ -655,66 +656,122 @@ static int __init enterprise_touch_init(void)
return 0;
}
-static struct usb_phy_plat_data tegra_usb_phy_pdata[] = {
- [0] = {
- .instance = 0,
- .vbus_gpio = -1,
- .vbus_reg_supply = "usb_vbus",
- .vbus_irq = ENT_TPS80031_IRQ_BASE +
- TPS80031_INT_VBUS_DET,
- },
- [1] = {
- .instance = 1,
- .vbus_gpio = -1,
- },
- [2] = {
- .instance = 2,
- .vbus_gpio = -1,
- },
-};
+static void enterprise_usb_hsic_postsupend(void)
+{
+ pr_debug("%s\n", __func__);
+#ifdef CONFIG_TEGRA_BB_XMM_POWER
+ baseband_xmm_set_power_status(BBXMM_PS_L2);
+#endif
+}
-static struct tegra_uhsic_config uhsic_phy_config = {
- .enable_gpio = -1,
- .reset_gpio = -1,
- .sync_start_delay = 9,
- .idle_wait_delay = 17,
- .term_range_adj = 0,
- .elastic_underrun_limit = 16,
- .elastic_overrun_limit = 16,
-};
+static void enterprise_usb_hsic_preresume(void)
+{
+ pr_debug("%s\n", __func__);
+#ifdef CONFIG_TEGRA_BB_XMM_POWER
+ baseband_xmm_set_power_status(BBXMM_PS_L2TOL0);
+#endif
+}
-static struct tegra_ehci_platform_data tegra_ehci_uhsic_pdata = {
- .phy_type = TEGRA_USB_PHY_TYPE_HSIC,
- .phy_config = &uhsic_phy_config,
- .operating_mode = TEGRA_USB_HOST,
- .power_down_on_bus_suspend = 1,
- .default_enable = true,
-};
+static void enterprise_usb_hsic_phy_power(void)
+{
+ pr_debug("%s\n", __func__);
+#ifdef CONFIG_TEGRA_BB_XMM_POWER
+ baseband_xmm_set_power_status(BBXMM_PS_L0);
+#endif
+}
-static struct tegra_ehci_platform_data tegra_ehci_pdata[] = {
- [0] = {
- .phy_config = &utmi_phy_config[0],
- .operating_mode = TEGRA_USB_HOST,
- .power_down_on_bus_suspend = 1,
- .default_enable = false,
- },
- [1] = {
- .phy_config = &utmi_phy_config[1],
- .operating_mode = TEGRA_USB_HOST,
- .power_down_on_bus_suspend = 1,
- .default_enable = false,
- },
- [2] = {
- .phy_config = &utmi_phy_config[2],
- .operating_mode = TEGRA_USB_HOST,
- .power_down_on_bus_suspend = 1,
- .default_enable = false,
- },
-};
+static void enterprise_usb_hsic_post_phy_off(void)
+{
+ pr_debug("%s\n", __func__);
+#ifdef CONFIG_TEGRA_BB_XMM_POWER
+ baseband_xmm_set_power_status(BBXMM_PS_L2);
+#endif
+}
-static struct tegra_otg_platform_data tegra_otg_pdata = {
+static struct tegra_usb_phy_platform_ops hsic_xmm_plat_ops = {
+ .post_suspend = enterprise_usb_hsic_postsupend,
+ .pre_resume = enterprise_usb_hsic_preresume,
+ .port_power = enterprise_usb_hsic_phy_power,
+ .post_phy_off = enterprise_usb_hsic_post_phy_off,
+};
+
+static struct tegra_usb_platform_data tegra_ehci2_hsic_xmm_pdata = {
+ .port_otg = false,
+ .has_hostpc = true,
+ .phy_intf = TEGRA_USB_PHY_INTF_HSIC,
+ .op_mode = TEGRA_USB_OPMODE_HOST,
+ .u_data.host = {
+ .vbus_gpio = -1,
+ .hot_plug = false,
+ .remote_wakeup_supported = false,
+ .power_off_on_suspend = false,
+ },
+ .u_cfg.hsic = {
+ .sync_start_delay = 9,
+ .idle_wait_delay = 17,
+ .term_range_adj = 0,
+ .elastic_underrun_limit = 16,
+ .elastic_overrun_limit = 16,
+ },
+ .ops = &hsic_xmm_plat_ops,
+};
+
+
+
+static struct tegra_usb_platform_data tegra_udc_pdata = {
+ .port_otg = true,
+ .has_hostpc = true,
+ .phy_intf = TEGRA_USB_PHY_INTF_UTMI,
+ .op_mode = TEGRA_USB_OPMODE_DEVICE,
+ .u_data.dev = {
+ .vbus_pmu_irq = ENT_TPS80031_IRQ_BASE +
+ TPS80031_INT_VBUS_DET,
+ .vbus_gpio = -1,
+ .charging_supported = false,
+ .remote_wakeup_supported = false,
+ },
+ .u_cfg.utmi = {
+ .hssync_start_delay = 0,
+ .elastic_limit = 16,
+ .idle_wait_delay = 17,
+ .term_range_adj = 6,
+ .xcvr_setup = 8,
+ .xcvr_lsfslew = 2,
+ .xcvr_lsrslew = 2,
+ .xcvr_setup_offset = 0,
+ .xcvr_use_fuses = 1,
+ },
+};
+
+static struct tegra_usb_platform_data tegra_ehci1_utmi_pdata = {
+ .port_otg = true,
+ .has_hostpc = true,
+ .builtin_host_disabled = true,
+ .phy_intf = TEGRA_USB_PHY_INTF_UTMI,
+ .op_mode = TEGRA_USB_OPMODE_HOST,
+ .u_data.host = {
+ .vbus_gpio = -1,
+ .vbus_reg = "usb_vbus",
+ .hot_plug = true,
+ .remote_wakeup_supported = true,
+ .power_off_on_suspend = true,
+ },
+ .u_cfg.utmi = {
+ .hssync_start_delay = 0,
+ .elastic_limit = 16,
+ .idle_wait_delay = 17,
+ .term_range_adj = 6,
+ .xcvr_setup = 15,
+ .xcvr_lsfslew = 2,
+ .xcvr_lsrslew = 2,
+ .xcvr_setup_offset = 0,
+ .xcvr_use_fuses = 1,
+ },
+};
+
+static struct tegra_usb_otg_data tegra_otg_pdata = {
.ehci_device = &tegra_ehci1_device,
- .ehci_pdata = &tegra_ehci_pdata[0],
+ .ehci_pdata = &tegra_ehci1_utmi_pdata,
};
struct platform_device *tegra_usb_hsic_host_register(void)
@@ -735,8 +792,8 @@ struct platform_device *tegra_usb_hsic_host_register(void)
pdev->dev.dma_mask = tegra_ehci2_device.dev.dma_mask;
pdev->dev.coherent_dma_mask = tegra_ehci2_device.dev.coherent_dma_mask;
- val = platform_device_add_data(pdev, &tegra_ehci_uhsic_pdata,
- sizeof(struct tegra_ehci_platform_data));
+ val = platform_device_add_data(pdev, &tegra_ehci2_hsic_xmm_pdata,
+ sizeof(struct tegra_usb_platform_data));
if (val)
goto error;
@@ -757,52 +814,12 @@ void tegra_usb_hsic_host_unregister(struct platform_device *pdev)
platform_device_unregister(pdev);
}
-static int enterprise_usb_hsic_postsupend(void)
-{
- pr_debug("%s\n", __func__);
-#ifdef CONFIG_TEGRA_BB_XMM_POWER
- baseband_xmm_set_power_status(BBXMM_PS_L2);
-#endif
- return 0;
-}
-
-static int enterprise_usb_hsic_preresume(void)
-{
- pr_debug("%s\n", __func__);
-#ifdef CONFIG_TEGRA_BB_XMM_POWER
- baseband_xmm_set_power_status(BBXMM_PS_L2TOL0);
-#endif
- return 0;
-}
-
-static int enterprise_usb_hsic_phy_ready(void)
-{
- pr_debug("%s\n", __func__);
-#ifdef CONFIG_TEGRA_BB_XMM_POWER
- baseband_xmm_set_power_status(BBXMM_PS_L0);
-#endif
- return 0;
-}
-
-static int enterprise_usb_hsic_phy_off(void)
-{
- pr_debug("%s\n", __func__);
-#ifdef CONFIG_TEGRA_BB_XMM_POWER
- baseband_xmm_set_power_status(BBXMM_PS_L3);
-#endif
- return 0;
-}
-
static void enterprise_usb_init(void)
{
- struct fsl_usb2_platform_data *udc_pdata;
-
- tegra_usb_phy_init(tegra_usb_phy_pdata, ARRAY_SIZE(tegra_usb_phy_pdata));
+ tegra_udc_device.dev.platform_data = &tegra_udc_pdata;
tegra_otg_device.dev.platform_data = &tegra_otg_pdata;
platform_device_register(&tegra_otg_device);
-
- udc_pdata = tegra_udc_device.dev.platform_data;
}
static struct platform_device *enterprise_audio_devices[] __initdata = {
@@ -836,11 +853,6 @@ static void enterprise_audio_init(void)
ARRAY_SIZE(enterprise_audio_devices));
}
-static void enterprise_gps_init(void)
-{
- tegra_gpio_enable(TEGRA_GPIO_PE4);
- tegra_gpio_enable(TEGRA_GPIO_PE5);
-}
static struct baseband_power_platform_data tegra_baseband_power_data = {
.baseband_type = BASEBAND_XMM,
@@ -912,61 +924,43 @@ static void enterprise_baseband_init(void)
enterprise_modem_init();
break;
case TEGRA_BB_XMM6260: /* XMM6260 HSIC */
- /* xmm baseband - do not switch off phy during suspend */
- tegra_ehci_uhsic_pdata.power_down_on_bus_suspend = 0;
- uhsic_phy_config.postsuspend = enterprise_usb_hsic_postsupend;
- uhsic_phy_config.preresume = enterprise_usb_hsic_preresume;
- uhsic_phy_config.usb_phy_ready = enterprise_usb_hsic_phy_ready;
- uhsic_phy_config.post_phy_off = enterprise_usb_hsic_phy_off;
- /* enable XMM6260 baseband gpio(s) */
- tegra_gpio_enable(tegra_baseband_power_data.modem.generic
- .mdm_reset);
- tegra_gpio_enable(tegra_baseband_power_data.modem.generic
- .mdm_on);
- tegra_gpio_enable(tegra_baseband_power_data.modem.generic
- .ap2mdm_ack);
- tegra_gpio_enable(tegra_baseband_power_data.modem.generic
- .mdm2ap_ack);
- tegra_gpio_enable(tegra_baseband_power_data.modem.generic
- .ap2mdm_ack2);
- tegra_gpio_enable(tegra_baseband_power_data.modem.generic
- .mdm2ap_ack2);
+ /* baseband-power.ko will register ehci2 device */
+ tegra_ehci2_device.dev.platform_data =
+ &tegra_ehci2_hsic_xmm_pdata;
tegra_baseband_power_data.hsic_register =
&tegra_usb_hsic_host_register;
tegra_baseband_power_data.hsic_unregister =
&tegra_usb_hsic_host_unregister;
+
platform_device_register(&tegra_baseband_power_device);
platform_device_register(&tegra_baseband_power2_device);
break;
#ifdef CONFIG_TEGRA_BB_M7400
case TEGRA_BB_M7400: /* M7400 HSIC */
- tegra_ehci_uhsic_pdata.power_down_on_bus_suspend = 0;
+ tegra_ehci2_hsic_xmm_pdata.u_data.host.power_off_on_suspend = 0;
tegra_ehci2_device.dev.platform_data
- = &tegra_ehci_uhsic_pdata;
+ = &tegra_ehci2_hsic_xmm_pdata;
platform_device_register(&tegra_baseband_m7400_device);
break;
#endif
}
}
-
static void enterprise_nfc_init(void)
{
struct board_info bi;
- tegra_gpio_enable(TEGRA_GPIO_PS4);
- tegra_gpio_enable(TEGRA_GPIO_PM6);
-
/* Enable firmware GPIO PX7 for board E1205 */
tegra_get_board_info(&bi);
if (bi.board_id == BOARD_E1205 && bi.fab >= BOARD_FAB_A03) {
nfc_pdata.firm_gpio = TEGRA_GPIO_PX7;
- tegra_gpio_enable(TEGRA_GPIO_PX7);
}
}
static void __init tegra_enterprise_init(void)
{
- tegra_thermal_init(&thermal_data);
+ tegra_thermal_init(&thermal_data,
+ throttle_list,
+ ARRAY_SIZE(throttle_list));
tegra_clk_init_from_table(enterprise_clk_init_table);
enterprise_pinmux_init();
enterprise_i2c_init();
@@ -980,9 +974,9 @@ static void __init tegra_enterprise_init(void)
enterprise_edp_init();
#endif
enterprise_kbc_init();
+ enterprise_nfc_init();
enterprise_touch_init();
enterprise_audio_init();
- enterprise_gps_init();
enterprise_baseband_init();
enterprise_panel_init();
enterprise_setup_bluesleep();
@@ -991,7 +985,7 @@ static void __init tegra_enterprise_init(void)
enterprise_suspend_init();
enterprise_bpc_mgmt_init();
tegra_release_bootloader_fb();
- enterprise_nfc_init();
+ tegra_serial_debug_init(TEGRA_UARTD_BASE, INT_WDT_CPU, NULL, -1, -1);
}
static void __init tegra_enterprise_reserve(void)
diff --git a/arch/arm/mach-tegra/board-enterprise.h b/arch/arm/mach-tegra/board-enterprise.h
index f47672091bf8..3c6d149abdff 100644
--- a/arch/arm/mach-tegra/board-enterprise.h
+++ b/arch/arm/mach-tegra/board-enterprise.h
@@ -158,4 +158,7 @@ enum tegra_bb_type {
TEGRA_BB_M7400,
};
+/* Indicate the pwm of backlight, DC pwm or external pwm3. */
+#define IS_EXTERNAL_PWM 0
+
#endif /*_MACH_TEGRA_BOARD_ENTERPRISE_H */
diff --git a/arch/arm/mach-tegra/board-harmony-panel.c b/arch/arm/mach-tegra/board-harmony-panel.c
index c24039652bc5..d4cd3f461b66 100644
--- a/arch/arm/mach-tegra/board-harmony-panel.c
+++ b/arch/arm/mach-tegra/board-harmony-panel.c
@@ -26,13 +26,14 @@
#include <mach/dc.h>
#include <mach/irqs.h>
#include <mach/iomap.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include <mach/tegra_fb.h>
#include <mach/fb.h>
#include "devices.h"
#include "gpio-names.h"
#include "board.h"
+#include "tegra2_host1x_devices.h"
#define harmony_bl_enb TEGRA_GPIO_PB5
#define harmony_lvds_shutdown TEGRA_GPIO_PB2
@@ -356,7 +357,7 @@ int __init harmony_panel_init(void)
#endif
#ifdef CONFIG_TEGRA_GRHOST
- err = nvhost_device_register(&tegra_grhost_device);
+ err = tegra2_register_host1x_devices();
if (err)
return err;
#endif
diff --git a/arch/arm/mach-tegra/board-harmony-pcie.c b/arch/arm/mach-tegra/board-harmony-pcie.c
index f3db0eeba2c9..f73cde4c5570 100644
--- a/arch/arm/mach-tegra/board-harmony-pcie.c
+++ b/arch/arm/mach-tegra/board-harmony-pcie.c
@@ -4,6 +4,8 @@
* Copyright (C) 2010 CompuLab, Ltd.
* Mike Rapoport <mike@compulab.co.il>
*
+ * Copyright (C) 2011-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.
@@ -68,7 +70,6 @@ int __init harmony_pcie_init(void)
return 0;
-err_pcie:
tegra_pinmux_set_tristate(TEGRA_PINGROUP_GPV, TEGRA_TRI_TRISTATE);
tegra_pinmux_set_tristate(TEGRA_PINGROUP_SLXA, TEGRA_TRI_TRISTATE);
tegra_pinmux_set_tristate(TEGRA_PINGROUP_SLXK, TEGRA_TRI_TRISTATE);
diff --git a/arch/arm/mach-tegra/board-harmony.c b/arch/arm/mach-tegra/board-harmony.c
index 9bf8cde056a3..dd14435cc17c 100644
--- a/arch/arm/mach-tegra/board-harmony.c
+++ b/arch/arm/mach-tegra/board-harmony.c
@@ -32,6 +32,9 @@
#include <linux/i2c-tegra.h>
#include <linux/memblock.h>
#include <linux/delay.h>
+#include <linux/mfd/tps6586x.h>
+#include <linux/platform_data/tegra_usb.h>
+#include <linux/tegra_uart.h>
#include <sound/wm8903.h>
@@ -81,20 +84,52 @@ static int __init parse_tag_nvidia(const struct tag *tag)
}
__tagtable(ATAG_NVIDIA, parse_tag_nvidia);
-static struct tegra_utmip_config utmi_phy_config = {
- .hssync_start_delay = 0,
- .idle_wait_delay = 17,
- .elastic_limit = 16,
- .term_range_adj = 6,
- .xcvr_setup = 9,
- .xcvr_lsfslew = 2,
- .xcvr_lsrslew = 2,
+
+static struct tegra_usb_platform_data tegra_udc_pdata = {
+ .port_otg = false,
+ .has_hostpc = false,
+ .phy_intf = TEGRA_USB_PHY_INTF_UTMI,
+ .op_mode = TEGRA_USB_OPMODE_DEVICE,
+ .u_data.dev = {
+ .vbus_pmu_irq = 0,
+ .vbus_gpio = -1,
+ .charging_supported = false,
+ .remote_wakeup_supported = false,
+ },
+ .u_cfg.utmi = {
+ .hssync_start_delay = 0,
+ .elastic_limit = 16,
+ .idle_wait_delay = 17,
+ .term_range_adj = 6,
+ .xcvr_setup = 8,
+ .xcvr_lsfslew = 2,
+ .xcvr_lsrslew = 2,
+ .xcvr_setup_offset = 0,
+ .xcvr_use_fuses = 1,
+ },
};
-static struct tegra_ehci_platform_data tegra_ehci_pdata = {
- .phy_config = &utmi_phy_config,
- .operating_mode = TEGRA_USB_HOST,
- .power_down_on_bus_suspend = 1,
+static struct tegra_usb_platform_data tegra_ehci3_utmi_pdata = {
+ .port_otg = false,
+ .has_hostpc = false,
+ .phy_intf = TEGRA_USB_PHY_INTF_UTMI,
+ .op_mode = TEGRA_USB_OPMODE_HOST,
+ .u_data.host = {
+ .vbus_gpio = TEGRA_GPIO_PD3,
+ .vbus_reg = NULL,
+ .hot_plug = true,
+ .remote_wakeup_supported = false,
+ .power_off_on_suspend = true,
+ },
+ .u_cfg.utmi = {
+ .hssync_start_delay = 9,
+ .elastic_limit = 16,
+ .idle_wait_delay = 17,
+ .term_range_adj = 6,
+ .xcvr_setup = 8,
+ .xcvr_lsfslew = 2,
+ .xcvr_lsrslew = 2,
+ },
};
static struct tegra_nand_chip_parms nand_chip_parms[] = {
@@ -283,39 +318,6 @@ static void __init harmony_i2c_init(void)
i2c_register_board_info(0, &wm8903_board_info, 1);
}
-/* OTG gadget device */
-/*static u64 tegra_otg_dmamask = DMA_BIT_MASK(32);
-
-
-static struct resource tegra_otg_resources[] = {
- [0] = {
- .start = TEGRA_USB_BASE,
- .end = TEGRA_USB_BASE + TEGRA_USB_SIZE - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = INT_USB,
- .end = INT_USB,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct fsl_usb2_platform_data tegra_otg_pdata = {
- .operating_mode = FSL_USB2_DR_DEVICE,
- .phy_mode = FSL_USB2_PHY_UTMI,
-};
-
-static struct platform_device tegra_otg = {
- .name = "fsl-tegra-udc",
- .id = -1,
- .dev = {
- .dma_mask = &tegra_otg_dmamask,
- .coherent_dma_mask = 0xffffffff,
- .platform_data = &tegra_otg_pdata,
- },
- .resource = tegra_otg_resources,
- .num_resources = ARRAY_SIZE(tegra_otg_resources),
-};*/
/* PDA power */
static struct pda_power_pdata pda_power_pdata = {
@@ -329,17 +331,36 @@ static struct platform_device pda_power_device = {
},
};
-static void harmony_debug_uart_init(void)
+static struct platform_device *harmony_uart_devices[] __initdata = {
+ &tegra_uartd_device,
+};
+
+static struct uart_clk_parent uart_parent_clk[] __initdata = {
+ [0] = {.name = "pll_p"},
+ [1] = {.name = "pll_m"},
+ [2] = {.name = "clk_m"},
+};
+
+static struct tegra_uart_platform_data harmony_uart_pdata;
+
+static void __init uart_debug_init(void)
{
+ unsigned long rate;
struct clk *c;
- debug_uart_clk = clk_get_sys("serial8250.0", "uartd");
+ /* UARTD is the debug port. */
+ pr_info("Selecting UARTD as the debug console\n");
+ harmony_uart_devices[0] = &debug_uartd_device;
debug_uart_port_base = ((struct plat_serial8250_port *)(
- debug_uartd_device.dev.platform_data))->mapbase;
+ debug_uartd_device.dev.platform_data))->mapbase;
+ debug_uart_clk = clk_get_sys("serial8250.0", "uartd");
+ /* Clock enable for the debug channel */
if (!IS_ERR_OR_NULL(debug_uart_clk)) {
+ rate = ((struct plat_serial8250_port *)(
+ debug_uartd_device.dev.platform_data))->uartclk;
pr_info("The debug console clock name is %s\n",
- debug_uart_clk->name);
+ debug_uart_clk->name);
c = tegra_get_clock_by_name("pll_p");
if (IS_ERR_OR_NULL(c))
pr_err("Not getting the parent clock pll_p\n");
@@ -347,16 +368,41 @@ static void harmony_debug_uart_init(void)
clk_set_parent(debug_uart_clk, c);
clk_enable(debug_uart_clk);
- clk_set_rate(debug_uart_clk, clk_get_rate(c));
+ clk_set_rate(debug_uart_clk, rate);
} else {
pr_err("Not getting the clock %s for debug console\n",
debug_uart_clk->name);
}
- return;
+}
+
+static void __init harmony_uart_init(void)
+{
+ int i;
+ struct clk *c;
+
+ for (i = 0; i < ARRAY_SIZE(uart_parent_clk); ++i) {
+ c = tegra_get_clock_by_name(uart_parent_clk[i].name);
+ if (IS_ERR_OR_NULL(c)) {
+ pr_err("Not able to get the clock for %s\n",
+ uart_parent_clk[i].name);
+ continue;
+ }
+ uart_parent_clk[i].parent_clk = c;
+ uart_parent_clk[i].fixed_clk_rate = clk_get_rate(c);
+ }
+ harmony_uart_pdata.parent_clk_list = uart_parent_clk;
+ harmony_uart_pdata.parent_clk_count = ARRAY_SIZE(uart_parent_clk);
+ tegra_uartd_device.dev.platform_data = &harmony_uart_pdata;
+
+ /* Register low speed only if it is selected */
+ if (!is_tegra_debug_uartport_hs())
+ uart_debug_init();
+
+ platform_add_devices(harmony_uart_devices,
+ ARRAY_SIZE(harmony_uart_devices));
}
static struct platform_device *harmony_devices[] __initdata = {
- &debug_uartd_device,
&tegra_sdhci_device1,
&tegra_sdhci_device2,
&tegra_sdhci_device4,
@@ -470,13 +516,14 @@ static void __init tegra_harmony_init(void)
harmony_keys_init();
- harmony_debug_uart_init();
+ harmony_uart_init();
tegra_sdhci_device1.dev.platform_data = &sdhci_pdata1;
tegra_sdhci_device2.dev.platform_data = &sdhci_pdata2;
tegra_sdhci_device4.dev.platform_data = &sdhci_pdata4;
- tegra_ehci3_device.dev.platform_data = &tegra_ehci_pdata;
+ tegra_udc_device.dev.platform_data = &tegra_udc_pdata;
+ tegra_ehci3_device.dev.platform_data = &tegra_ehci3_utmi_pdata;
platform_add_devices(harmony_devices, ARRAY_SIZE(harmony_devices));
harmony_i2c_init();
diff --git a/arch/arm/mach-tegra/board-kai-kbc.c b/arch/arm/mach-tegra/board-kai-kbc.c
index 928e5de707c9..7f0efdf572b2 100644
--- a/arch/arm/mach-tegra/board-kai-kbc.c
+++ b/arch/arm/mach-tegra/board-kai-kbc.c
@@ -86,17 +86,7 @@ static struct platform_device kai_keys_device = {
int __init kai_keys_init(void)
{
- int i;
-
pr_info("Registering gpio keys\n");
-
- /* Enable gpio mode for other pins */
- for (i = 0; i < kai_keys_platform_data.nbuttons; i++) {
- if (kai_keys_platform_data.buttons[i].gpio < 0)
- continue;
- tegra_gpio_enable(kai_keys_platform_data.buttons[i].gpio);
- }
-
platform_device_register(&kai_keys_device);
return 0;
diff --git a/arch/arm/mach-tegra/board-kai-panel.c b/arch/arm/mach-tegra/board-kai-panel.c
index 53661ced7c8e..e16b17c919ee 100644
--- a/arch/arm/mach-tegra/board-kai-panel.c
+++ b/arch/arm/mach-tegra/board-kai-panel.c
@@ -27,7 +27,7 @@
#include <linux/pwm_backlight.h>
#include <asm/atomic.h>
#include <linux/nvhost.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include <mach/irqs.h>
#include <mach/iomap.h>
#include <mach/dc.h>
@@ -37,6 +37,7 @@
#include "board-kai.h"
#include "devices.h"
#include "gpio-names.h"
+#include "tegra3_host1x_devices.h"
/* kai default display board pins */
#define kai_lvds_avdd_en TEGRA_GPIO_PH6
@@ -111,8 +112,6 @@ static int kai_backlight_init(struct device *dev)
if (WARN_ON(ARRAY_SIZE(kai_bl_output_measured) != 256))
pr_err("bl_output array does not have 256 elements\n");
- tegra_gpio_disable(kai_bl_pwm);
-
ret = gpio_request(kai_bl_enb, "backlight_enb");
if (ret < 0)
return ret;
@@ -120,8 +119,6 @@ static int kai_backlight_init(struct device *dev)
ret = gpio_direction_output(kai_bl_enb, 1);
if (ret < 0)
gpio_free(kai_bl_enb);
- else
- tegra_gpio_enable(kai_bl_enb);
return ret;
};
@@ -132,7 +129,6 @@ static void kai_backlight_exit(struct device *dev)
/*ret = gpio_request(kai_bl_enb, "backlight_enb");*/
gpio_set_value(kai_bl_enb, 0);
gpio_free(kai_bl_enb);
- tegra_gpio_disable(kai_bl_enb);
return;
}
@@ -177,7 +173,7 @@ static struct platform_device kai_backlight_device = {
},
};
-static int kai_panel_enable(void)
+static int kai_panel_postpoweron(void)
{
if (kai_lvds_reg == NULL) {
kai_lvds_reg = regulator_get(NULL, "vdd_lvds");
@@ -188,15 +184,6 @@ static int kai_panel_enable(void)
regulator_enable(kai_lvds_reg);
}
- if (kai_lvds_vdd_panel == NULL) {
- kai_lvds_vdd_panel = regulator_get(NULL, "vdd_lcd_panel");
- if (WARN_ON(IS_ERR(kai_lvds_vdd_panel)))
- pr_err("%s: couldn't get regulator vdd_lcd_panel: %ld\n",
- __func__, PTR_ERR(kai_lvds_vdd_panel));
- else
- regulator_enable(kai_lvds_vdd_panel);
- }
-
mdelay(5);
gpio_set_value(kai_lvds_avdd_en, 1);
@@ -212,8 +199,31 @@ static int kai_panel_enable(void)
return 0;
}
+static int kai_panel_enable(void)
+{
+ if (kai_lvds_vdd_panel == NULL) {
+ kai_lvds_vdd_panel = regulator_get(NULL, "vdd_lcd_panel");
+ if (WARN_ON(IS_ERR(kai_lvds_vdd_panel)))
+ pr_err("%s: couldn't get regulator vdd_lcd_panel: %ld\n",
+ __func__, PTR_ERR(kai_lvds_vdd_panel));
+ else
+ regulator_enable(kai_lvds_vdd_panel);
+ }
+
+ return 0;
+}
+
static int kai_panel_disable(void)
{
+ regulator_disable(kai_lvds_vdd_panel);
+ regulator_put(kai_lvds_vdd_panel);
+ kai_lvds_vdd_panel = NULL;
+
+ return 0;
+}
+
+static int kai_panel_prepoweroff(void)
+{
gpio_set_value(kai_lvds_lr, 0);
gpio_set_value(kai_lvds_shutdown, 0);
gpio_set_value(kai_lvds_rst, 0);
@@ -227,10 +237,6 @@ static int kai_panel_disable(void)
regulator_put(kai_lvds_reg);
kai_lvds_reg = NULL;
- regulator_disable(kai_lvds_vdd_panel);
- regulator_put(kai_lvds_vdd_panel);
- kai_lvds_vdd_panel = NULL;
-
return 0;
}
@@ -530,6 +536,8 @@ static struct tegra_dc_out kai_disp1_out = {
.n_modes = ARRAY_SIZE(kai_panel_modes),
.enable = kai_panel_enable,
+ .postpoweron = kai_panel_postpoweron,
+ .prepoweroff = kai_panel_prepoweroff,
.disable = kai_panel_disable,
};
@@ -620,27 +628,17 @@ static void kai_panel_early_suspend(struct early_suspend *h)
fb_blank(registered_fb[0], FB_BLANK_POWERDOWN);
if (num_registered_fb > 1)
fb_blank(registered_fb[1], FB_BLANK_NORMAL);
-
#ifdef CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND
- cpufreq_save_default_governor();
- cpufreq_set_conservative_governor();
- cpufreq_set_conservative_governor_param("up_threshold",
- SET_CONSERVATIVE_GOVERNOR_UP_THRESHOLD);
-
- cpufreq_set_conservative_governor_param("down_threshold",
- SET_CONSERVATIVE_GOVERNOR_DOWN_THRESHOLD);
-
- cpufreq_set_conservative_governor_param("freq_step",
- SET_CONSERVATIVE_GOVERNOR_FREQ_STEP);
+ cpufreq_store_default_gov();
+ cpufreq_change_gov(cpufreq_conservative_gov);
#endif
-
}
static void kai_panel_late_resume(struct early_suspend *h)
{
unsigned i;
#ifdef CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND
- cpufreq_restore_default_governor();
+ cpufreq_restore_default_gov();
#endif
for (i = 0; i < num_registered_fb; i++)
fb_blank(registered_fb[i], FB_BLANK_UNBLANK);
@@ -661,35 +659,27 @@ int __init kai_panel_init(void)
#endif
gpio_request(kai_lvds_avdd_en, "lvds_avdd_en");
gpio_direction_output(kai_lvds_avdd_en, 1);
- tegra_gpio_enable(kai_lvds_avdd_en);
gpio_request(kai_lvds_stdby, "lvds_stdby");
gpio_direction_output(kai_lvds_stdby, 1);
- tegra_gpio_enable(kai_lvds_stdby);
gpio_request(kai_lvds_rst, "lvds_rst");
gpio_direction_output(kai_lvds_rst, 1);
- tegra_gpio_enable(kai_lvds_rst);
if (board_info.fab == BOARD_FAB_A00) {
gpio_request(kai_lvds_rs_a00, "lvds_rs");
gpio_direction_output(kai_lvds_rs_a00, 0);
- tegra_gpio_enable(kai_lvds_rs_a00);
} else {
gpio_request(kai_lvds_rs, "lvds_rs");
gpio_direction_output(kai_lvds_rs, 0);
- tegra_gpio_enable(kai_lvds_rs);
}
gpio_request(kai_lvds_lr, "lvds_lr");
gpio_direction_output(kai_lvds_lr, 1);
- tegra_gpio_enable(kai_lvds_lr);
gpio_request(kai_lvds_shutdown, "lvds_shutdown");
gpio_direction_output(kai_lvds_shutdown, 1);
- tegra_gpio_enable(kai_lvds_shutdown);
- tegra_gpio_enable(kai_hdmi_hpd);
gpio_request(kai_hdmi_hpd, "hdmi_hpd");
gpio_direction_input(kai_hdmi_hpd);
@@ -701,7 +691,7 @@ int __init kai_panel_init(void)
#endif
#ifdef CONFIG_TEGRA_GRHOST
- err = nvhost_device_register(&tegra_grhost_device);
+ err = tegra3_register_host1x_devices();
if (err)
return err;
#endif
diff --git a/arch/arm/mach-tegra/board-kai-pinmux.c b/arch/arm/mach-tegra/board-kai-pinmux.c
index 1bc64bdb1558..be11d4ef6698 100644
--- a/arch/arm/mach-tegra/board-kai-pinmux.c
+++ b/arch/arm/mach-tegra/board-kai-pinmux.c
@@ -379,7 +379,7 @@ static __initdata struct tegra_pingroup_config kai_pinmux_common[] = {
DEFAULT_PINMUX(SPI2_MISO, SPI2, NORMAL, NORMAL, INPUT),
DEFAULT_PINMUX(SPI2_MOSI, SPI2, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(KB_ROW11, KBC, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(KB_ROW11, KBC, PULL_UP, TRISTATE, INPUT),
DEFAULT_PINMUX(KB_ROW12, KBC, NORMAL, TRISTATE, OUTPUT),
DEFAULT_PINMUX(KB_ROW13, KBC, NORMAL, TRISTATE, OUTPUT),
};
@@ -449,13 +449,9 @@ static __initdata struct tegra_pingroup_config unused_pins_lowpower[] = {
static void __init kai_pinmux_audio_init(void)
{
- tegra_gpio_enable(TEGRA_GPIO_CDC_IRQ);
gpio_request(TEGRA_GPIO_CDC_IRQ, "rt5640");
gpio_direction_input(TEGRA_GPIO_CDC_IRQ);
- tegra_gpio_enable(TEGRA_GPIO_HP_DET);
- tegra_gpio_enable(TEGRA_GPIO_INT_MIC_EN);
- tegra_gpio_enable(TEGRA_GPIO_EXT_MIC_EN);
}
/* We are disabling this code for now. */
@@ -469,6 +465,7 @@ static void __init kai_pinmux_audio_init(void)
static struct gpio_init_pin_info init_gpio_mode_kai_common[] = {
GPIO_INIT_PIN_MODE(TEGRA_GPIO_PDD7, false, 0),
GPIO_INIT_PIN_MODE(TEGRA_GPIO_PCC6, false, 0),
+ GPIO_INIT_PIN_MODE(TEGRA_GPIO_PCC7, false, 1),
};
static void __init kai_gpio_init_configure(void)
@@ -550,7 +547,6 @@ static void set_unused_pin_gpio(struct gpio_init_pin_info *lpm_pin_info,
gpio_free(pin_info->gpio_nr);
continue;
}
- tegra_gpio_enable(pin_info->gpio_nr);
}
}
diff --git a/arch/arm/mach-tegra/board-kai-power.c b/arch/arm/mach-tegra/board-kai-power.c
index f397963dba60..6c66f1d2bbe9 100644
--- a/arch/arm/mach-tegra/board-kai-power.c
+++ b/arch/arm/mach-tegra/board-kai-power.c
@@ -40,7 +40,6 @@
#include "board.h"
#include "board-kai.h"
#include "pm.h"
-#include "wakeups-t3.h"
#include "tegra3_tsensor.h"
#define PMC_CTRL 0x0
@@ -178,16 +177,16 @@ static struct max77663_regulator_fps_cfg max77663_fps_cfgs[] = {
}
MAX77663_PDATA_INIT(sd0, 600000, 3387500, NULL, 1, 0, 0,
- 0, 0, -1, FPS_SRC_NONE, -1, -1, EN2_CTRL_SD0 | SD_FSRADE_DISABLE);
+ 0, 0, -1, FPS_SRC_NONE, -1, -1, EN2_CTRL_SD0);
MAX77663_PDATA_INIT(sd1, 800000, 1587500, NULL, 1, 0, 0,
- 1, 1, -1, FPS_SRC_1, -1, -1, SD_FSRADE_DISABLE);
+ 1, 1, -1, FPS_SRC_1, FPS_POWER_PERIOD_1, FPS_POWER_PERIOD_6, 0);
MAX77663_PDATA_INIT(sd2, 1800000, 1800000, NULL, 1, 0, 0,
- 1, 1, -1, FPS_SRC_NONE, -1, -1, 0);
+ 1, 1, -1, FPS_SRC_0, -1, -1, 0);
MAX77663_PDATA_INIT(sd3, 600000, 3387500, NULL, 1, 0, 0,
- 1, 1, -1, FPS_SRC_NONE, -1, -1, 0);
+ 1, 1, -1, FPS_SRC_0, -1, -1, 0);
MAX77663_PDATA_INIT(ldo0, 800000, 2350000, max77663_rails(sd3), 1, 0, 0,
1, 1, -1, FPS_SRC_1, -1, -1, 0);
@@ -199,10 +198,10 @@ MAX77663_PDATA_INIT(ldo2, 800000, 3950000, NULL, 1, 0, 0,
1, 1, -1, FPS_SRC_1, -1, -1, 0);
MAX77663_PDATA_INIT(ldo3, 800000, 3950000, NULL, 1, 0, 0,
- 1, 1, -1, FPS_SRC_NONE, -1, -1, 0);
+ 1, 1, -1, FPS_SRC_1, -1, -1, 0);
MAX77663_PDATA_INIT(ldo4, 800000, 1587500, NULL, 0, 0, 0,
- 1, 1, 1000000, FPS_SRC_NONE, -1, -1, LDO4_EN_TRACKING);
+ 1, 1, 1000000, FPS_SRC_0, -1, -1, LDO4_EN_TRACKING);
MAX77663_PDATA_INIT(ldo5, 800000, 2800000, NULL, 0, 0, 0,
1, 1, -1, FPS_SRC_NONE, -1, -1, 0);
@@ -272,9 +271,9 @@ static struct max77663_gpio_config max77663_gpio_cfgs[] = {
{
.gpio = MAX77663_GPIO3,
.dir = GPIO_DIR_OUT,
- .dout = GPIO_DOUT_HIGH,
+ .dout = GPIO_DOUT_LOW,
.out_drv = GPIO_OUT_DRV_OPEN_DRAIN,
- .alternate = GPIO_ALT_DISABLE,
+ .alternate = GPIO_ALT_ENABLE,
},
{
.gpio = MAX77663_GPIO4,
@@ -485,7 +484,7 @@ FIXED_REG(4, en_vddio_vid_a01, en_vddio_vid, NULL,
FIXED_REG(5, en_3v3_modem_a01, en_3v3_modem, NULL,
0, 1, TEGRA_GPIO_PP0, true, 0, 3300);
FIXED_REG(6, en_vdd_pnl_a01, en_vdd_pnl, FIXED_SUPPLY(en_3v3_sys_a01),
- 0, 0, TEGRA_GPIO_PW1, true, 0, 3300);
+ 0, 1, TEGRA_GPIO_PW1, true, 0, 3300);
FIXED_REG(7, en_cam3_ldo_a01, en_cam3_ldo, FIXED_SUPPLY(en_3v3_sys_a01),
0, 0, TEGRA_GPIO_PR7, true, 0, 3300);
FIXED_REG(8, en_vdd_com_a01, en_vdd_com, FIXED_SUPPLY(en_3v3_sys_a01),
@@ -567,8 +566,6 @@ static int __init kai_fixed_regulator_init(void)
fixed_reg_devs[i]->dev.platform_data;
gpio_nr = fixed_reg_pdata->gpio;
- if (gpio_nr < TEGRA_NR_GPIOS)
- tegra_gpio_enable(gpio_nr);
}
return platform_add_devices(fixed_reg_devs, nfixreg_devs);
diff --git a/arch/arm/mach-tegra/board-kai-sdhci.c b/arch/arm/mach-tegra/board-kai-sdhci.c
index 2a346fa20d4c..0fa39ccf475d 100644
--- a/arch/arm/mach-tegra/board-kai-sdhci.c
+++ b/arch/arm/mach-tegra/board-kai-sdhci.c
@@ -106,6 +106,7 @@ static struct tegra_sdhci_platform_data tegra_sdhci_platform_data2 = {
.mmc_data = {
.register_status_notify = kai_wifi_status_register,
.built_in = 0,
+ .ocr_mask = MMC_OCR_1V8_MASK,
},
#ifndef CONFIG_MMC_EMBEDDED_SDIO
.pm_flags = MMC_PM_KEEP_POWER,
@@ -113,8 +114,9 @@ static struct tegra_sdhci_platform_data tegra_sdhci_platform_data2 = {
.cd_gpio = -1,
.wp_gpio = -1,
.power_gpio = -1,
-/* .tap_delay = 6,
- .is_voltage_switch_supported = false,
+ .tap_delay = 0x0F,
+ .ddr_clk_limit = 41000000,
+/* .is_voltage_switch_supported = false,
.vdd_rail_name = NULL,
.slot_rail_name = NULL,
.vdd_max_uv = -1,
@@ -128,8 +130,9 @@ static struct tegra_sdhci_platform_data tegra_sdhci_platform_data0 = {
.cd_gpio = KAI_SD_CD,
.wp_gpio = -1,
.power_gpio = -1,
-/* .tap_delay = 6,
- .is_voltage_switch_supported = true,
+ .tap_delay = 0x0F,
+ .ddr_clk_limit = 41000000,
+/* .is_voltage_switch_supported = true,
.vdd_rail_name = "vddio_sdmmc1",
.slot_rail_name = "vddio_sd_slot",
.vdd_max_uv = 3320000,
@@ -144,11 +147,11 @@ static struct tegra_sdhci_platform_data tegra_sdhci_platform_data3 = {
.power_gpio = -1,
.is_8bit = 1,
.tap_delay = 0x0F,
+ .ddr_clk_limit = 41000000,
.mmc_data = {
.built_in = 1,
}
-/* .tap_delay = 6,
- .is_voltage_switch_supported = false,
+/* .is_voltage_switch_supported = false,
.vdd_rail_name = NULL,
.slot_rail_name = NULL,
.vdd_max_uv = -1,
@@ -241,9 +244,6 @@ static int __init kai_wifi_init(void)
if (rc)
pr_err("WLAN_IRQ gpio request failed:%d\n", rc);
- tegra_gpio_enable(KAI_WLAN_EN);
- tegra_gpio_enable(KAI_WLAN_IRQ);
-
rc = gpio_direction_output(KAI_WLAN_EN, 0);
if (rc)
pr_err("WLAN_EN gpio direction configuration failed:%d\n", rc);
diff --git a/arch/arm/mach-tegra/board-kai-sensors.c b/arch/arm/mach-tegra/board-kai-sensors.c
index df260a5ec5c5..29d1bea2e8a7 100644
--- a/arch/arm/mach-tegra/board-kai-sensors.c
+++ b/arch/arm/mach-tegra/board-kai-sensors.c
@@ -21,11 +21,14 @@
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/i2c.h>
+#include <linux/nct1008.h>
#include <linux/cm3217.h>
#include <linux/mpu.h>
#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
#include <asm/mach-types.h>
#include <mach/gpio.h>
+#include <mach/thermal.h>
#include <media/ov2710.h>
#include "board.h"
#include "board-kai.h"
@@ -34,6 +37,108 @@
static struct regulator *kai_1v8_cam3;
static struct regulator *kai_vdd_cam3;
+#ifndef CONFIG_TEGRA_INTERNAL_TSENSOR_EDP_SUPPORT
+static int nct_get_temp(void *_data, long *temp)
+{
+ struct nct1008_data *data = _data;
+ return nct1008_thermal_get_temp(data, temp);
+}
+
+static int nct_get_temp_low(void *_data, long *temp)
+{
+ struct nct1008_data *data = _data;
+ return nct1008_thermal_get_temp_low(data, temp);
+}
+
+static int nct_set_limits(void *_data,
+ long lo_limit_milli,
+ long hi_limit_milli)
+{
+ struct nct1008_data *data = _data;
+ return nct1008_thermal_set_limits(data,
+ lo_limit_milli,
+ hi_limit_milli);
+}
+
+static int nct_set_alert(void *_data,
+ void (*alert_func)(void *),
+ void *alert_data)
+{
+ struct nct1008_data *data = _data;
+ return nct1008_thermal_set_alert(data, alert_func, alert_data);
+}
+
+static int nct_set_shutdown_temp(void *_data, long shutdown_temp)
+{
+ struct nct1008_data *data = _data;
+ return nct1008_thermal_set_shutdown_temp(data, shutdown_temp);
+}
+
+static void nct1008_probe_callback(struct nct1008_data *data)
+{
+ struct tegra_thermal_device *thermal_device;
+
+ thermal_device = kzalloc(sizeof(struct tegra_thermal_device),
+ GFP_KERNEL);
+ if (!thermal_device) {
+ pr_err("unable to allocate thermal device\n");
+ return;
+ }
+
+ thermal_device->name = "nct72";
+ thermal_device->data = data;
+ thermal_device->id = THERMAL_DEVICE_ID_NCT_EXT;
+ thermal_device->offset = TDIODE_OFFSET;
+ thermal_device->get_temp = nct_get_temp;
+ thermal_device->get_temp_low = nct_get_temp_low;
+ thermal_device->set_limits = nct_set_limits;
+ thermal_device->set_alert = nct_set_alert;
+ thermal_device->set_shutdown_temp = nct_set_shutdown_temp;
+
+ tegra_thermal_device_register(thermal_device);
+}
+#endif
+
+static struct nct1008_platform_data kai_nct1008_pdata = {
+ .supported_hwrev = true,
+ .ext_range = true,
+ .conv_rate = 0x09, /* 0x09 corresponds to 32Hz conversion rate */
+ .offset = 8, /* 4 * 2C. 1C for device accuracies */
+#ifndef CONFIG_TEGRA_INTERNAL_TSENSOR_EDP_SUPPORT
+ .probe_callback = nct1008_probe_callback,
+#endif
+};
+
+static struct i2c_board_info kai_i2c4_nct1008_board_info[] = {
+ {
+ I2C_BOARD_INFO("nct72", 0x4C),
+ .platform_data = &kai_nct1008_pdata,
+ .irq = -1,
+ }
+};
+
+static int kai_nct1008_init(void)
+{
+ int ret = 0;
+
+ /* FIXME: enable irq when throttling is supported */
+ kai_i2c4_nct1008_board_info[0].irq =
+ TEGRA_GPIO_TO_IRQ(KAI_TEMP_ALERT_GPIO);
+
+ ret = gpio_request(KAI_TEMP_ALERT_GPIO, "temp_alert");
+ if (ret < 0) {
+ pr_err("%s: gpio_request failed\n", __func__);
+ return ret;
+ }
+
+ ret = gpio_direction_input(KAI_TEMP_ALERT_GPIO);
+ if (ret < 0) {
+ pr_err("%s: set gpio to input failed\n", __func__);
+ gpio_free(KAI_TEMP_ALERT_GPIO);
+ }
+ return ret;
+}
+
static struct cm3217_platform_data kai_cm3217_pdata = {
.levels = {10, 160, 225, 320, 640, 1280, 2600, 5800, 8000, 10240},
.golden_adc = 0,
@@ -51,7 +156,6 @@ static int kai_camera_init(void)
{
int ret;
- tegra_gpio_enable(CAM2_POWER_DWN_GPIO);
ret = gpio_request(CAM2_POWER_DWN_GPIO, "cam2_power_en");
if (ret < 0) {
pr_err("%s: gpio_request failed for gpio %s\n",
@@ -61,7 +165,6 @@ static int kai_camera_init(void)
gpio_direction_output(CAM2_POWER_DWN_GPIO, 1);
mdelay(10);
- tegra_gpio_enable(CAM2_RST_GPIO);
ret = gpio_request(CAM2_RST_GPIO, "cam2_reset");
if (ret < 0) {
pr_err("%s: gpio_request failed for gpio %s\n",
@@ -207,7 +310,6 @@ static void mpuirq_init(void)
#if (MPU_GYRO_TYPE == MPU_TYPE_MPU3050)
#if MPU_ACCEL_IRQ_GPIO
/* ACCEL-IRQ assignment */
- tegra_gpio_enable(MPU_ACCEL_IRQ_GPIO);
ret = gpio_request(MPU_ACCEL_IRQ_GPIO, MPU_ACCEL_NAME);
if (ret < 0) {
pr_err("%s: gpio_request failed %d\n", __func__, ret);
@@ -224,7 +326,6 @@ static void mpuirq_init(void)
#endif
/* MPU-IRQ assignment */
- tegra_gpio_enable(MPU_GYRO_IRQ_GPIO);
ret = gpio_request(MPU_GYRO_IRQ_GPIO, MPU_GYRO_NAME);
if (ret < 0) {
pr_err("%s: gpio_request failed %d\n", __func__, ret);
@@ -245,6 +346,15 @@ static void mpuirq_init(void)
int __init kai_sensors_init(void)
{
+ int err;
+
+ err = kai_nct1008_init();
+ if (err)
+ pr_err("%s: nct1008 init failed\n", __func__);
+ else
+ i2c_register_board_info(4, kai_i2c4_nct1008_board_info,
+ ARRAY_SIZE(kai_i2c4_nct1008_board_info));
+
kai_camera_init();
i2c_register_board_info(2, kai_i2c2_board_info,
diff --git a/arch/arm/mach-tegra/board-kai.c b/arch/arm/mach-tegra/board-kai.c
index 38f12f9313d1..bf4ae415072d 100644
--- a/arch/arm/mach-tegra/board-kai.c
+++ b/arch/arm/mach-tegra/board-kai.c
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/board-kai.c
*
- * 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 version 2 as
@@ -56,70 +56,74 @@
#include <asm/mach/arch.h>
#include <mach/usb_phy.h>
#include <mach/thermal.h>
+#include <mach/tegra_fiq_debugger.h>
#include "board.h"
#include "clock.h"
#include "board-kai.h"
+#include "board-touch.h"
#include "devices.h"
#include "gpio-names.h"
#include "fuse.h"
#include "pm.h"
#include "wdt-recovery.h"
+static struct balanced_throttle throttle_list[] = {
+ {
+ .id = BALANCED_THROTTLE_ID_TJ,
+ .throt_tab_size = 10,
+ .throt_tab = {
+ { 0, 1000 },
+ { 640000, 1000 },
+ { 640000, 1000 },
+ { 640000, 1000 },
+ { 640000, 1000 },
+ { 640000, 1000 },
+ { 760000, 1000 },
+ { 760000, 1050 },
+ {1000000, 1050 },
+ {1000000, 1100 },
+ },
+ },
+#ifdef CONFIG_TEGRA_SKIN_THROTTLE
+ {
+ .id = BALANCED_THROTTLE_ID_SKIN,
+ .throt_tab_size = 6,
+ .throt_tab = {
+ { 640000, 1200 },
+ { 640000, 1200 },
+ { 760000, 1200 },
+ { 760000, 1200 },
+ {1000000, 1200 },
+ {1000000, 1200 },
+ },
+ },
+#endif
+};
+
/* All units are in millicelsius */
static struct tegra_thermal_data thermal_data = {
- .temp_throttle = 85000,
+ .shutdown_device_id = THERMAL_DEVICE_ID_NCT_EXT,
.temp_shutdown = 90000,
- .temp_offset = TDIODE_OFFSET, /* temps based on tdiode */
+#if defined(CONFIG_TEGRA_EDP_LIMITS) || defined(CONFIG_TEGRA_THERMAL_THROTTLE)
+ .throttle_edp_device_id = THERMAL_DEVICE_ID_NCT_EXT,
+#endif
#ifdef CONFIG_TEGRA_EDP_LIMITS
.edp_offset = TDIODE_OFFSET, /* edp based on tdiode */
.hysteresis_edp = 3000,
#endif
-#ifdef CONFIG_TEGRA_THERMAL_SYSFS
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
+ .temp_throttle = 85000,
.tc1 = 0,
.tc2 = 1,
.passive_delay = 2000,
-#else
- .hysteresis_throttle = 1000,
+#endif
+#ifdef CONFIG_TEGRA_SKIN_THROTTLE
+ .skin_device_id = THERMAL_DEVICE_ID_SKIN,
+ .temp_throttle_skin = 43000,
#endif
};
-/* !!!TODO: Change for kai (Taken from Ventana) */
-static struct tegra_utmip_config utmi_phy_config[] = {
- [0] = {
- .hssync_start_delay = 0,
- .idle_wait_delay = 17,
- .elastic_limit = 16,
- .term_range_adj = 6,
- .xcvr_setup = 15,
- .xcvr_setup_offset = 0,
- .xcvr_use_fuses = 1,
- .xcvr_lsfslew = 2,
- .xcvr_lsrslew = 2,
- },
- [1] = {
- .hssync_start_delay = 0,
- .idle_wait_delay = 17,
- .elastic_limit = 16,
- .term_range_adj = 6,
- .xcvr_setup = 15,
- .xcvr_setup_offset = 0,
- .xcvr_use_fuses = 1,
- .xcvr_lsfslew = 2,
- .xcvr_lsrslew = 2,
- },
- [2] = {
- .hssync_start_delay = 0,
- .idle_wait_delay = 17,
- .elastic_limit = 16,
- .term_range_adj = 6,
- .xcvr_setup = 8,
- .xcvr_setup_offset = 0,
- .xcvr_use_fuses = 1,
- .xcvr_lsfslew = 2,
- .xcvr_lsrslew = 2,
- },
-};
/* wl128x BT, FM, GPS connectivity chip */
struct ti_st_plat_data kai_wilink_pdata = {
@@ -146,11 +150,16 @@ static noinline void __init kai_bt_st(void)
platform_device_register(&wl128x_device);
platform_device_register(&btwilink_device);
- tegra_gpio_enable(TEGRA_GPIO_PU0);
}
static struct resource kai_bluesleep_resources[] = {
[0] = {
+ .name = "gpio_host_wake",
+ .start = TEGRA_GPIO_PU6,
+ .end = TEGRA_GPIO_PU6,
+ .flags = IORESOURCE_IO,
+ },
+ [1] = {
.name = "host_wake",
.start = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PU6),
.end = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PU6),
@@ -159,7 +168,7 @@ static struct resource kai_bluesleep_resources[] = {
};
static struct platform_device kai_bluesleep_device = {
- .name = "tibluesleep",
+ .name = "bluesleep",
.id = 0,
.num_resources = ARRAY_SIZE(kai_bluesleep_resources),
.resource = kai_bluesleep_resources,
@@ -168,7 +177,6 @@ static struct platform_device kai_bluesleep_device = {
static noinline void __init kai_tegra_setup_tibluesleep(void)
{
platform_device_register(&kai_bluesleep_device);
- tegra_gpio_enable(TEGRA_GPIO_PU6);
}
static __initdata struct tegra_clk_init_table kai_clk_init_table[] = {
@@ -296,11 +304,17 @@ static struct regulator_consumer_supply smb349_vbus_supply[] = {
REGULATOR_SUPPLY("usb_bat_chg", NULL),
};
+static struct regulator_consumer_supply smb349_otg_vbus_supply[] = {
+ REGULATOR_SUPPLY("usb_vbus_otg", NULL),
+};
+
static struct smb349_charger_platform_data smb349_charger_pdata = {
.max_charge_current_mA = 1000,
.charging_term_current_mA = 100,
.consumer_supplies = smb349_vbus_supply,
.num_consumer_supplies = ARRAY_SIZE(smb349_vbus_supply),
+ .otg_consumer_supplies = smb349_otg_vbus_supply,
+ .num_otg_consumer_supplies = ARRAY_SIZE(smb349_otg_vbus_supply),
};
static struct i2c_board_info kai_i2c4_smb349_board_info[] = {
@@ -496,7 +510,6 @@ static struct platform_device tegra_camera = {
};
static struct platform_device *kai_spi_devices[] __initdata = {
- &tegra_spi_device4,
&tegra_spi_device1,
};
@@ -510,11 +523,11 @@ static struct spi_clk_parent spi_parent_clk[] = {
#endif
};
-static struct tegra_spi_platform_data kai_spi_pdata = {
- .is_dma_based = true,
- .max_dma_buffer = (16 * 1024),
- .is_clkon_always = false,
- .max_rate = 100000000,
+static struct tegra_spi_platform_data kai_spi1_pdata = {
+ .is_dma_based = true,
+ .max_dma_buffer = (128),
+ .is_clkon_always = false,
+ .max_rate = 100000000,
};
static void __init kai_spi_init(void)
@@ -532,9 +545,10 @@ static void __init kai_spi_init(void)
spi_parent_clk[i].parent_clk = c;
spi_parent_clk[i].fixed_clk_rate = clk_get_rate(c);
}
- kai_spi_pdata.parent_clk_list = spi_parent_clk;
- kai_spi_pdata.parent_clk_count = ARRAY_SIZE(spi_parent_clk);
- tegra_spi_device4.dev.platform_data = &kai_spi_pdata;
+
+ kai_spi1_pdata.parent_clk_list = spi_parent_clk;
+ kai_spi1_pdata.parent_clk_count = ARRAY_SIZE(spi_parent_clk);
+ tegra_spi_device1.dev.platform_data = &kai_spi1_pdata;
platform_add_devices(kai_spi_devices,
ARRAY_SIZE(kai_spi_devices));
@@ -607,7 +621,9 @@ static struct platform_device *kai_devices[] __initdata = {
#if defined(CONFIG_TEGRA_IOVMM_SMMU) || defined(CONFIG_TEGRA_IOMMU_SMMU)
&tegra_smmu_device,
#endif
- &tegra_wdt_device,
+ &tegra_wdt0_device,
+ &tegra_wdt1_device,
+ &tegra_wdt2_device,
#if defined(CONFIG_TEGRA_AVP)
&tegra_avp_device,
#endif
@@ -651,9 +667,6 @@ static int __init kai_touch_init(void)
{
int touch_id;
- tegra_gpio_enable(KAI_TS_ID1);
- tegra_gpio_enable(KAI_TS_ID2);
-
gpio_request(KAI_TS_ID1, "touch-id1");
gpio_direction_input(KAI_TS_ID1);
@@ -697,47 +710,97 @@ static int __init kai_touch_init(void)
return 0;
}
-static struct tegra_ehci_platform_data tegra_ehci_pdata[] = {
- [0] = {
- .phy_config = &utmi_phy_config[0],
- .operating_mode = TEGRA_USB_HOST,
- .power_down_on_bus_suspend = 1,
- .default_enable = true,
+static struct tegra_usb_platform_data tegra_udc_pdata = {
+ .port_otg = true,
+ .has_hostpc = true,
+ .phy_intf = TEGRA_USB_PHY_INTF_UTMI,
+ .op_mode = TEGRA_USB_OPMODE_DEVICE,
+ .u_data.dev = {
+ .vbus_pmu_irq = 0,
+ .vbus_gpio = -1,
+ .charging_supported = false,
+ .remote_wakeup_supported = false,
},
- [1] = {
- .phy_config = &utmi_phy_config[1],
- .operating_mode = TEGRA_USB_HOST,
- .power_down_on_bus_suspend = 1,
- .default_enable = false,
+ .u_cfg.utmi = {
+ .hssync_start_delay = 0,
+ .elastic_limit = 16,
+ .idle_wait_delay = 17,
+ .term_range_adj = 6,
+ .xcvr_setup = 8,
+ .xcvr_lsfslew = 2,
+ .xcvr_lsrslew = 2,
+ .xcvr_setup_offset = 0,
+ .xcvr_use_fuses = 1,
},
};
-static struct tegra_otg_platform_data tegra_otg_pdata = {
- .ehci_device = &tegra_ehci1_device,
- .ehci_pdata = &tegra_ehci_pdata[0],
+static struct tegra_usb_platform_data tegra_ehci1_utmi_pdata = {
+ .port_otg = true,
+ .has_hostpc = true,
+ .phy_intf = TEGRA_USB_PHY_INTF_UTMI,
+ .op_mode = TEGRA_USB_OPMODE_HOST,
+ .u_data.host = {
+ .vbus_gpio = -1,
+ .vbus_reg = "usb_vbus_otg",
+ .hot_plug = true,
+ .remote_wakeup_supported = true,
+ .power_off_on_suspend = true,
+ },
+ .u_cfg.utmi = {
+ .hssync_start_delay = 0,
+ .elastic_limit = 16,
+ .idle_wait_delay = 17,
+ .term_range_adj = 6,
+ .xcvr_setup = 15,
+ .xcvr_lsfslew = 2,
+ .xcvr_lsrslew = 2,
+ .xcvr_setup_offset = 0,
+ .xcvr_use_fuses = 1,
+ },
};
-#ifdef CONFIG_USB_SUPPORT
-static struct usb_phy_plat_data tegra_usb_phy_pdata[] = {
- [0] = {
- .instance = 0,
- .vbus_gpio = -1,
+
+static struct tegra_usb_platform_data tegra_ehci2_utmi_pdata = {
+ .port_otg = false,
+ .has_hostpc = true,
+ .phy_intf = TEGRA_USB_PHY_INTF_UTMI,
+ .op_mode = TEGRA_USB_OPMODE_HOST,
+ .u_data.host = {
+ .vbus_gpio = -1,
+ .vbus_reg = NULL,
+ .hot_plug = false,
+ .remote_wakeup_supported = true,
+ .power_off_on_suspend = true,
+
},
- [1] = {
- .instance = 1,
- .vbus_gpio = -1,
+ .u_cfg.utmi = {
+ .hssync_start_delay = 0,
+ .elastic_limit = 16,
+ .idle_wait_delay = 17,
+ .term_range_adj = 6,
+ .xcvr_setup = 8,
+ .xcvr_lsfslew = 2,
+ .xcvr_lsrslew = 2,
+ .xcvr_setup_offset = 0,
+ .xcvr_use_fuses = 1,
},
};
+static struct tegra_usb_otg_data tegra_otg_pdata = {
+ .ehci_device = &tegra_ehci1_device,
+ .ehci_pdata = &tegra_ehci1_utmi_pdata,
+};
+
+#if CONFIG_USB_SUPPORT
static void kai_usb_init(void)
{
- tegra_usb_phy_init(tegra_usb_phy_pdata,
- ARRAY_SIZE(tegra_usb_phy_pdata));
-
tegra_otg_device.dev.platform_data = &tegra_otg_pdata;
platform_device_register(&tegra_otg_device);
- tegra_ehci2_device.dev.platform_data = &tegra_ehci_pdata[1];
+ /* Setup the udc platform data */
+ tegra_udc_device.dev.platform_data = &tegra_udc_pdata;
+
+ tegra_ehci2_device.dev.platform_data = &tegra_ehci2_utmi_pdata;
platform_device_register(&tegra_ehci2_device);
}
@@ -745,10 +808,6 @@ static void kai_modem_init(void)
{
int ret;
- tegra_gpio_enable(TEGRA_GPIO_W_DISABLE);
- tegra_gpio_enable(TEGRA_GPIO_MODEM_RSVD1);
- tegra_gpio_enable(TEGRA_GPIO_MODEM_RSVD2);
-
ret = gpio_request(TEGRA_GPIO_W_DISABLE, "w_disable_gpio");
if (ret < 0)
pr_err("%s: gpio_request failed for gpio %d\n",
@@ -794,16 +853,11 @@ static void kai_audio_init(void)
}
}
-static void kai_nfc_init(void)
-{
- tegra_gpio_enable(TEGRA_GPIO_PX0);
- tegra_gpio_enable(TEGRA_GPIO_PS7);
- tegra_gpio_enable(TEGRA_GPIO_PR3);
-}
-
static void __init tegra_kai_init(void)
{
- tegra_thermal_init(&thermal_data);
+ tegra_thermal_init(&thermal_data,
+ throttle_list,
+ ARRAY_SIZE(throttle_list));
tegra_clk_init_from_table(kai_clk_init_table);
kai_pinmux_init();
kai_i2c_init();
@@ -813,7 +867,6 @@ static void __init tegra_kai_init(void)
kai_edp_init();
#endif
kai_uart_init();
- kai_tsensor_init();
kai_audio_init();
platform_add_devices(kai_devices, ARRAY_SIZE(kai_devices));
tegra_ram_console_debug_init();
@@ -823,9 +876,8 @@ static void __init tegra_kai_init(void)
kai_touch_init();
kai_keys_init();
kai_panel_init();
- kai_bt_st();
kai_tegra_setup_tibluesleep();
- kai_nfc_init();
+ kai_bt_st();
kai_sensors_init();
kai_pins_state_init();
kai_emc_init();
@@ -834,6 +886,7 @@ static void __init tegra_kai_init(void)
#ifdef CONFIG_TEGRA_WDT_RECOVERY
tegra_wdt_recovery_init();
#endif
+ tegra_serial_debug_init(TEGRA_UARTD_BASE, INT_WDT_CPU, NULL, -1, -1);
}
static void __init kai_ramconsole_reserve(unsigned long size)
diff --git a/arch/arm/mach-tegra/board-kai.h b/arch/arm/mach-tegra/board-kai.h
index 1f7c16ebf590..5039b972d000 100644
--- a/arch/arm/mach-tegra/board-kai.h
+++ b/arch/arm/mach-tegra/board-kai.h
@@ -81,7 +81,6 @@ int kai_pins_state_init(void);
int kai_emc_init(void);
int kai_edp_init(void);
void __init kai_tsensor_init(void);
-int __init touch_init_raydium(int irq_gpio, int reset_gpio, int platform);
int __init touch_init_synaptics_kai(void);
#define TOUCH_GPIO_IRQ_RAYDIUM_SPI TEGRA_GPIO_PZ3
@@ -95,6 +94,8 @@ int __init touch_init_synaptics_kai(void);
#define KAI_TS_ID1_PG TEGRA_PINGROUP_GMI_WAIT
#define KAI_TS_ID2_PG TEGRA_PINGROUP_GMI_WP_N
+#define KAI_TEMP_ALERT_GPIO TEGRA_GPIO_PS3
+
#define MPU_TYPE_MPU3050 1
#define MPU_TYPE_MPU6050 2
#define MPU_GYRO_TYPE MPU_TYPE_MPU6050
diff --git a/arch/arm/mach-tegra/board-p1852-panel.c b/arch/arm/mach-tegra/board-p1852-panel.c
index 8940af0c0b62..4e86476cdd2c 100644
--- a/arch/arm/mach-tegra/board-p1852-panel.c
+++ b/arch/arm/mach-tegra/board-p1852-panel.c
@@ -20,7 +20,7 @@
#include <asm/mach-types.h>
#include <linux/platform_device.h>
#include <linux/nvhost.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include <mach/irqs.h>
#include <mach/iomap.h>
#include <mach/dc.h>
@@ -28,6 +28,7 @@
#include "board.h"
#include "devices.h"
+#include "tegra3_host1x_devices.h"
static int p1852_panel_enable(void)
{
@@ -39,6 +40,63 @@ static int p1852_panel_disable(void)
return 0;
}
+#ifdef CONFIG_TOUCHSCREEN_ATMEL_MXT
+
+static struct tegra_dc_mode p1852_panel_modes[] = {
+ {
+ /* 1366x768@60Hz */
+ .pclk = 74180000,
+ .h_ref_to_sync = 1,
+ .v_ref_to_sync = 1,
+ .h_sync_width = 30,
+ .v_sync_width = 5,
+ .h_back_porch = 52,
+ .v_back_porch = 20,
+ .h_active = 1366,
+ .v_active = 768,
+ .h_front_porch = 64,
+ .v_front_porch = 25,
+ },
+ {
+ /* 1366x768@50Hz */
+ .pclk = 74180000,
+ .h_ref_to_sync = 1,
+ .v_ref_to_sync = 1,
+ .h_sync_width = 30,
+ .v_sync_width = 5,
+ .h_back_porch = 56,
+ .v_back_porch = 80,
+ .h_active = 1366,
+ .v_active = 768,
+ .h_front_porch = 64,
+ .v_front_porch = 125,
+ },
+ {
+ /* 1366x768@48 */
+ .pclk = 74180000,
+ .h_ref_to_sync = 1,
+ .v_ref_to_sync = 1,
+ .h_sync_width = 30,
+ .v_sync_width = 5,
+ .h_back_porch = 52,
+ .v_back_porch = 98,
+ .h_active = 1366,
+ .v_active = 768,
+ .h_front_porch = 64,
+ .v_front_porch = 152,
+ },
+};
+
+static struct tegra_fb_data p1852_fb_data = {
+ .win = 0,
+ .xres = 1366,
+ .yres = 768,
+ .bits_per_pixel = 32,
+};
+
+#else
+
+/* Mode data for primary RGB/LVDS out */
static struct tegra_dc_mode p1852_panel_modes[] = {
{
/* 800x480@60 */
@@ -63,6 +121,8 @@ static struct tegra_fb_data p1852_fb_data = {
.bits_per_pixel = 32,
};
+#endif
+
static struct tegra_dc_out p1852_disp1_out = {
.align = TEGRA_DC_ALIGN_MSB,
.order = TEGRA_DC_ORDER_RED_BLUE,
@@ -126,7 +186,7 @@ int __init p1852_panel_init(void)
res->end = tegra_fb_start + tegra_fb_size - 1;
#ifdef CONFIG_TEGRA_GRHOST
- err = nvhost_device_register(&tegra_grhost_device);
+ err = tegra3_register_host1x_devices();
if (err)
return err;
#endif
diff --git a/arch/arm/mach-tegra/board-p1852-pinmux.c b/arch/arm/mach-tegra/board-p1852-pinmux.c
index a59f6590e332..21f310b0ef16 100644
--- a/arch/arm/mach-tegra/board-p1852-pinmux.c
+++ b/arch/arm/mach-tegra/board-p1852-pinmux.c
@@ -63,14 +63,21 @@
/* !!!FIXME!!!! Update drive strength with characterized value */
static __initdata struct tegra_drive_pingroup_config p1852_drive_pinmux[] = {
- SET_DRIVE(DAP2, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST),
+ /* ATC1 CFG */
+ SET_DRIVE(AT1, ENABLE, ENABLE, DIV_1, 0, 0, SLOWEST, SLOWEST),
+ /* ATC2 CFG */
+ SET_DRIVE(AT2, ENABLE, ENABLE, DIV_1, 0, 0, SLOWEST, SLOWEST),
+ /* ATC3 CFG */
+ SET_DRIVE(AT3, ENABLE, ENABLE, DIV_1, 0, 0, SLOWEST, SLOWEST),
+ /* ATC4 CFG */
+ SET_DRIVE(AT4, DISABLE, DISABLE, DIV_1, 0, 0, SLOWEST, SLOWEST),
/* All I2C pins are driven to maximum drive strength */
/* GEN1 I2C */
SET_DRIVE(DBG, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST),
/* GEN2 I2C */
- SET_DRIVE(AT5, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST),
+ SET_DRIVE(AT5, DISABLE, ENABLE, DIV_1, 12, 30, FASTEST, FASTEST),
/* DDC I2C */
SET_DRIVE(DDC, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST),
@@ -83,6 +90,48 @@ static __initdata struct tegra_drive_pingroup_config p1852_drive_pinmux[] = {
SET_DRIVE(GMF, DISABLE, ENABLE, DIV_1, 0, 0, SLOWEST, SLOWEST),
SET_DRIVE(GMG, DISABLE, ENABLE, DIV_1, 15, 6, SLOWEST, SLOWEST),
SET_DRIVE(GMH, DISABLE, ENABLE, DIV_1, 12, 6, SLOWEST, SLOWEST),
+
+ /* LCD */
+ SET_DRIVE(LCD1, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST),
+ SET_DRIVE(LCD2, DISABLE, ENABLE, DIV_1, 2, 2, FASTEST, FASTEST),
+
+ /* DAP2 */
+ SET_DRIVE(DAP2, ENABLE, ENABLE, DIV_1, 0, 0, SLOWEST, SLOWEST),
+ /* DAP4 */
+ SET_DRIVE(DAP4, ENABLE, ENABLE, DIV_1, 0, 0, SLOWEST, SLOWEST),
+ /* DBG */
+ SET_DRIVE(DBG, ENABLE, ENABLE, DIV_1, 20, 0, SLOWEST, SLOWEST),
+ /* SPI */
+ SET_DRIVE(SPI, ENABLE, ENABLE, DIV_1, 0, 0, SLOWEST, SLOWEST),
+ /* UAA */
+ SET_DRIVE(UAA, DISABLE, DISABLE, DIV_1, 0, 0, SLOWEST, SLOWEST),
+ /* UART2 */
+ SET_DRIVE(UART2, ENABLE, ENABLE, DIV_1, 0, 0, SLOWEST, SLOWEST),
+ /* UART3 */
+ SET_DRIVE(UART3, ENABLE, ENABLE, DIV_1, 0, 0, SLOWEST, SLOWEST),
+ /* GME */
+ SET_DRIVE(GME, DISABLE, ENABLE, DIV_1, 1, 4, SLOWEST, SLOWEST),
+ /* GMF */
+ SET_DRIVE(GMF, DISABLE, ENABLE, DIV_1, 0, 0, SLOWEST, SLOWEST),
+ /* GMG */
+ SET_DRIVE(GMG, DISABLE, ENABLE, DIV_1, 3, 0, SLOWEST, SLOWEST),
+ /* GMH */
+ SET_DRIVE(GMH, DISABLE, ENABLE, DIV_1, 0, 12, SLOWEST, SLOWEST),
+
+ /* I2S/TDM */
+#ifdef CONFIG_TEGRA_MODS
+ SET_DRIVE(DAP1, ENABLE, ENABLE, DIV_1, 20, 20, SLOWEST, SLOWEST),
+ SET_DRIVE(DAP3, ENABLE, ENABLE, DIV_1, 20, 20, SLOWEST, SLOWEST),
+#else
+ SET_DRIVE(DAP1, ENABLE, ENABLE, DIV_1, 3, 3, SLOWEST, SLOWEST),
+ SET_DRIVE(DAP3, ENABLE, ENABLE, DIV_1, 3, 3, SLOWEST, SLOWEST),
+#endif
+
+ /* SPI */
+ SET_DRIVE(UAD, DISABLE, ENABLE, DIV_1, 4, 1, SLOWEST, SLOWEST),
+ SET_DRIVE(UAB, DISABLE, ENABLE, DIV_1, 4, 1, SLOWEST, SLOWEST),
+ SET_DRIVE(SDIO3, DISABLE, ENABLE, DIV_8, 4, 1, FASTEST, FASTEST),
+
};
#define DEFAULT_PINMUX(_pingroup, _mux, _pupd, _tri, _io) \
@@ -121,6 +170,21 @@ static __initdata struct tegra_drive_pingroup_config p1852_drive_pinmux[] = {
.ioreset = TEGRA_PIN_IO_RESET_##_ioreset \
}
+/* For LV(Low voltage) pad groups which has IO_RESET bit */
+#define LVPAD_PINMUX(_pingroup, _mux, _pupd, _tri, _io, _lock, _ioreset) \
+ { \
+ .pingroup = TEGRA_PINGROUP_##_pingroup, \
+ .func = TEGRA_MUX_##_mux, \
+ .pupd = TEGRA_PUPD_##_pupd, \
+ .tristate = TEGRA_TRI_##_tri, \
+ .io = TEGRA_PIN_##_io, \
+ .lock = TEGRA_PIN_LOCK_##_lock, \
+ .od = TEGRA_PIN_OD_DEFAULT, \
+ .ioreset = TEGRA_PIN_IO_RESET_##_ioreset \
+ }
+
+
+
static __initdata struct tegra_pingroup_config p1852_pinmux_common[] = {
/* SDMMC1 pinmux */
DEFAULT_PINMUX(SDMMC1_CLK, SDMMC1, NORMAL, NORMAL, INPUT),
@@ -142,14 +206,6 @@ static __initdata struct tegra_pingroup_config p1852_pinmux_common[] = {
DEFAULT_PINMUX(KB_ROW8, SDMMC2, PULL_UP, NORMAL, INPUT),
DEFAULT_PINMUX(KB_ROW9, SDMMC2, PULL_UP, NORMAL, INPUT),
- /* SDMMC3 pinmux */
- DEFAULT_PINMUX(SDMMC3_CLK, SDMMC3, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(SDMMC3_CMD, SDMMC3, PULL_UP, NORMAL, INPUT),
- DEFAULT_PINMUX(SDMMC3_DAT0, SDMMC3, PULL_UP, NORMAL, INPUT),
- DEFAULT_PINMUX(SDMMC3_DAT1, SDMMC3, PULL_UP, NORMAL, INPUT),
- DEFAULT_PINMUX(SDMMC3_DAT2, SDMMC3, PULL_UP, NORMAL, INPUT),
- DEFAULT_PINMUX(SDMMC3_DAT3, SDMMC3, PULL_UP, NORMAL, INPUT),
-
/* SDMMC4 pinmux */
DEFAULT_PINMUX(CAM_MCLK, POPSDMMC4, NORMAL, NORMAL, INPUT),
DEFAULT_PINMUX(GPIO_PCC1, POPSDMMC4, NORMAL, NORMAL, INPUT),
@@ -161,6 +217,7 @@ static __initdata struct tegra_pingroup_config p1852_pinmux_common[] = {
DEFAULT_PINMUX(GPIO_PBB5, POPSDMMC4, PULL_UP, NORMAL, INPUT),
DEFAULT_PINMUX(GPIO_PBB6, POPSDMMC4, PULL_UP, NORMAL, INPUT),
DEFAULT_PINMUX(GPIO_PBB7, POPSDMMC4, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PCC2, POPSDMMC4, PULL_UP, NORMAL, INPUT),
/* UART1 pinmux */
DEFAULT_PINMUX(ULPI_DATA0, UARTA, NORMAL, NORMAL, OUTPUT),
@@ -179,10 +236,10 @@ static __initdata struct tegra_pingroup_config p1852_pinmux_common[] = {
DEFAULT_PINMUX(GMI_A19, UARTD, NORMAL, NORMAL, OUTPUT),
/* UART5 pinmux */
- DEFAULT_PINMUX(SDMMC4_DAT0, UARTE, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(SDMMC4_DAT1, UARTE, NORMAL, NORMAL, OUTPUT),
- DEFAULT_PINMUX(SDMMC4_DAT2, UARTE, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(SDMMC4_DAT3, UARTE, NORMAL, NORMAL, OUTPUT),
+ LVPAD_PINMUX(SDMMC4_DAT0, UARTE, NORMAL, NORMAL, OUTPUT, DISABLE, DISABLE),
+ LVPAD_PINMUX(SDMMC4_DAT1, UARTE, NORMAL, NORMAL, INPUT, DISABLE, DISABLE),
+ LVPAD_PINMUX(SDMMC4_DAT2, UARTE, NORMAL, NORMAL, INPUT, DISABLE, DISABLE),
+ LVPAD_PINMUX(SDMMC4_DAT3, UARTE, NORMAL, NORMAL, OUTPUT, DISABLE, DISABLE),
/* I2C1 pinmux */
I2C_PINMUX(GEN1_I2C_SCL, I2C1, NORMAL, NORMAL, INPUT, DISABLE, ENABLE),
@@ -212,6 +269,12 @@ static __initdata struct tegra_pingroup_config p1852_pinmux_common[] = {
DEFAULT_PINMUX(ULPI_DATA6, SPI2, NORMAL, NORMAL, INPUT),
DEFAULT_PINMUX(ULPI_DATA7, SPI2, NORMAL, NORMAL, INPUT),
+ /* SPI3 pinmux */
+ DEFAULT_PINMUX(SDMMC3_CLK, SPI3, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC3_DAT0, SPI3, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC3_DAT1, SPI3, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC3_DAT2, SPI3, NORMAL, NORMAL, INPUT),
+
/* SPDIF pinmux */
DEFAULT_PINMUX(SPDIF_IN, SPDIF, NORMAL, NORMAL, INPUT),
@@ -228,10 +291,10 @@ static __initdata struct tegra_pingroup_config p1852_pinmux_common[] = {
DEFAULT_PINMUX(DAP3_SCLK, I2S2, NORMAL, NORMAL, INPUT),
/* DAP3 */
- DEFAULT_PINMUX(SDMMC4_DAT4, I2S4, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(SDMMC4_DAT5, I2S4, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(SDMMC4_DAT6, I2S4, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(SDMMC4_DAT7, I2S4, NORMAL, NORMAL, INPUT),
+ LVPAD_PINMUX(SDMMC4_DAT4, I2S4, NORMAL, NORMAL, INPUT, DISABLE, DISABLE),
+ LVPAD_PINMUX(SDMMC4_DAT5, I2S4, NORMAL, NORMAL, INPUT, DISABLE, DISABLE),
+ LVPAD_PINMUX(SDMMC4_DAT6, I2S4, NORMAL, NORMAL, INPUT, DISABLE, DISABLE),
+ LVPAD_PINMUX(SDMMC4_DAT7, I2S4, NORMAL, NORMAL, INPUT, DISABLE, DISABLE),
/* NOR pinmux */
DEFAULT_PINMUX(GMI_AD0, GMI, NORMAL, NORMAL, INPUT),
@@ -250,8 +313,8 @@ static __initdata struct tegra_pingroup_config p1852_pinmux_common[] = {
DEFAULT_PINMUX(GMI_AD13, GMI, NORMAL, NORMAL, INPUT),
DEFAULT_PINMUX(GMI_AD14, GMI, NORMAL, NORMAL, INPUT),
DEFAULT_PINMUX(GMI_AD15, GMI, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(GMI_ADV_N, GMI, NORMAL, NORMAL, OUTPUT),
- DEFAULT_PINMUX(GMI_CLK, GMI, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GMI_ADV_N, NAND, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GMI_CLK, NAND, NORMAL, NORMAL, OUTPUT),
DEFAULT_PINMUX(GMI_CS0_N, GMI, NORMAL, NORMAL, OUTPUT),
DEFAULT_PINMUX(GMI_OE_N, GMI, NORMAL, NORMAL, OUTPUT),
DEFAULT_PINMUX(GMI_RST_N, GMI, NORMAL, NORMAL, OUTPUT),
@@ -327,29 +390,50 @@ static __initdata struct tegra_pingroup_config p1852_pinmux_common[] = {
DEFAULT_PINMUX(PEX_L2_RST_N, PCIE, NORMAL, NORMAL, OUTPUT),
DEFAULT_PINMUX(PEX_L2_CLKREQ_N, PCIE, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(CLK1_OUT, EXTPERIPH1, PULL_DOWN, NORMAL, INPUT),
+
VI_PINMUX(VI_D2, VI, NORMAL, NORMAL, INPUT, DISABLE, DISABLE),
VI_PINMUX(VI_D3, VI, NORMAL, NORMAL, INPUT, DISABLE, DISABLE),
- VI_PINMUX(VI_D4, VI, NORMAL, NORMAL, OUTPUT, DISABLE, DISABLE),
+ VI_PINMUX(VI_D4, VI, NORMAL, NORMAL, INPUT, DISABLE, DISABLE),
VI_PINMUX(VI_D5, VI, NORMAL, NORMAL, INPUT, DISABLE, DISABLE),
- VI_PINMUX(VI_D6, VI, NORMAL, NORMAL, OUTPUT, DISABLE, DISABLE),
+ VI_PINMUX(VI_D6, VI, NORMAL, NORMAL, INPUT, DISABLE, DISABLE),
VI_PINMUX(VI_D7, VI, NORMAL, NORMAL, INPUT, DISABLE, DISABLE),
VI_PINMUX(VI_D8, VI, NORMAL, NORMAL, INPUT, DISABLE, DISABLE),
VI_PINMUX(VI_D9, VI, NORMAL, NORMAL, INPUT, DISABLE, DISABLE),
VI_PINMUX(VI_PCLK, VI, PULL_UP, TRISTATE, INPUT, DISABLE, DISABLE),
/* pin config for gpios */
- DEFAULT_PINMUX(VI_D0, SAFE, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(CLK1_OUT, RSVD1, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(CLK1_REQ, RSVD2, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(LCD_SCK, SPI5, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(LCD_DC1, RSVD1, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(SDMMC3_DAT4, SDMMC3, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(SDMMC3_DAT5, SDMMC3, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(SPI2_CS1_N, SPI2, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(SPDIF_OUT, SAFE, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(SPI1_SCK, GMI, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(SPI1_CS0_N, GMI, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(SPI1_MISO, SAFE, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(VI_D0, SAFE, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(CLK1_REQ, RSVD2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_SCK, SPI5, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_DC1, RSVD1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC3_DAT5, SDMMC3, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SPDIF_OUT, SAFE, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SPI1_SCK, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SPI1_CS0_N, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SPI1_MISO, RSVD3, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SPI2_CS2_N, SPI2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PV0, RSVD, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PV1, RSVD, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(CRT_HSYNC, RSVD1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(CRT_VSYNC, RSVD1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_CS0_N, RSVD, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_M1, RSVD1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_PWR0, SPI5, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_PWR1, RSVD1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_PWR2, SPI5, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_SDIN, RSVD, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_SDOUT, SPI5, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PV2, RSVD1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PV3, RSVD1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC3_DAT7, SDMMC3, NORMAL, NORMAL, INPUT),
+ LVPAD_PINMUX(SDMMC4_CLK, NAND, NORMAL, NORMAL, INPUT, DISABLE, DISABLE),
+ DEFAULT_PINMUX(SDMMC3_CMD, SDMMC3, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC3_DAT3, RSVD0, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(VI_D1, RSVD1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC3_DAT4, SDMMC3, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(SPI2_CS1_N, SPI2, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(HDMI_INT, RSVD0, NORMAL, TRISTATE, INPUT),
};
int __init p1852_pinmux_init(void)
@@ -361,31 +445,58 @@ int __init p1852_pinmux_init(void)
return 0;
}
-static struct gpio p1852_sku8_gpios[] = {
- {TEGRA_GPIO_PW4, GPIOF_OUT_INIT_HIGH, "w4"},
- {TEGRA_GPIO_PEE2, GPIOF_OUT_INIT_HIGH, "ee2"},
- {TEGRA_GPIO_PZ4, GPIOF_OUT_INIT_HIGH, "z4"},
- {TEGRA_GPIO_PD2, GPIOF_OUT_INIT_HIGH, "d2"},
- {TEGRA_GPIO_PD1, GPIOF_OUT_INIT_HIGH, "d1"},
- {TEGRA_GPIO_PD0, GPIOF_OUT_INIT_HIGH, "d0"},
- {TEGRA_GPIO_PW3, GPIOF_IN, "therm_alert"},
- {TEGRA_GPIO_PK5, GPIOF_OUT_INIT_HIGH, "user1"},
- {TEGRA_GPIO_PX5, GPIOF_OUT_INIT_HIGH, "user2"},
- {TEGRA_GPIO_PX6, GPIOF_OUT_INIT_HIGH, "user3"},
- {TEGRA_GPIO_PX7, GPIOF_OUT_INIT_HIGH, "user4"},
+#define GPIO_INIT_PIN_MODE(_gpio, _is_input, _value) \
+ { \
+ .gpio_nr = _gpio, \
+ .is_input = _is_input, \
+ .value = _value, \
+ }
+
+static struct gpio_init_pin_info p1852_sku8_gpios[] = {
+ GPIO_INIT_PIN_MODE(TEGRA_GPIO_PT4, false, 1),
+ GPIO_INIT_PIN_MODE(TEGRA_GPIO_PEE2, false, 1),
+ GPIO_INIT_PIN_MODE(TEGRA_GPIO_PZ4, false, 1),
+ GPIO_INIT_PIN_MODE(TEGRA_GPIO_PD2, false, 1),
+ GPIO_INIT_PIN_MODE(TEGRA_GPIO_PD0, true, 0),
+ GPIO_INIT_PIN_MODE(TEGRA_GPIO_PW3, true, 0),
+ GPIO_INIT_PIN_MODE(TEGRA_GPIO_PK5, false, 1),
+ GPIO_INIT_PIN_MODE(TEGRA_GPIO_PX5, false, 1),
+ GPIO_INIT_PIN_MODE(TEGRA_GPIO_PX6, false, 1),
+ GPIO_INIT_PIN_MODE(TEGRA_GPIO_PX7, false, 1),
+ GPIO_INIT_PIN_MODE(TEGRA_GPIO_PV0, false, 1),
+ GPIO_INIT_PIN_MODE(TEGRA_GPIO_PV1, false, 1),
+ GPIO_INIT_PIN_MODE(TEGRA_GPIO_PV6, false, 1),
+ GPIO_INIT_PIN_MODE(TEGRA_GPIO_PV7, true, 0),
+ GPIO_INIT_PIN_MODE(TEGRA_GPIO_PN4, false, 1),
+ GPIO_INIT_PIN_MODE(TEGRA_GPIO_PN6, false, 1),
+ GPIO_INIT_PIN_MODE(TEGRA_GPIO_PW1, false, 1),
+ GPIO_INIT_PIN_MODE(TEGRA_GPIO_PB2, false, 1),
+ GPIO_INIT_PIN_MODE(TEGRA_GPIO_PC1, false, 1),
+ GPIO_INIT_PIN_MODE(TEGRA_GPIO_PC6, true, 0),
+ GPIO_INIT_PIN_MODE(TEGRA_GPIO_PZ2, false, 1),
+ GPIO_INIT_PIN_MODE(TEGRA_GPIO_PN5, false, 1),
+ GPIO_INIT_PIN_MODE(TEGRA_GPIO_PDD3, false, 1),
+ GPIO_INIT_PIN_MODE(TEGRA_GPIO_PV2, true, 0),
+ GPIO_INIT_PIN_MODE(TEGRA_GPIO_PV3, true, 0),
+ GPIO_INIT_PIN_MODE(TEGRA_GPIO_PD4, true, 0),
+ GPIO_INIT_PIN_MODE(TEGRA_GPIO_PCC4, false, 0),
+ GPIO_INIT_PIN_MODE(TEGRA_GPIO_PA7, false, 1),
+ GPIO_INIT_PIN_MODE(TEGRA_GPIO_PB4, false, 1),
+ GPIO_INIT_PIN_MODE(TEGRA_GPIO_PD5, false, 1),
+ GPIO_INIT_PIN_MODE(TEGRA_GPIO_PN7, true, 0),
};
int __init p1852_gpio_init(void)
{
int i, pin_count = 0;
- struct gpio *gpios_info = NULL;
+ struct gpio_init_pin_info *gpios_info = NULL;
gpios_info = p1852_sku8_gpios;
pin_count = ARRAY_SIZE(p1852_sku8_gpios);
- gpio_request_array(gpios_info, pin_count);
- for (i = 0; i < pin_count; i++) {
- tegra_gpio_enable(gpios_info[i].gpio);
- gpio_export(gpios_info[i].gpio, true);
+ for (i = 0; i < pin_count; ++i) {
+ tegra_gpio_init_configure(gpios_info->gpio_nr,
+ gpios_info->is_input, gpios_info->value);
+ gpios_info++;
}
return 0;
}
diff --git a/arch/arm/mach-tegra/board-p1852-sdhci.c b/arch/arm/mach-tegra/board-p1852-sdhci.c
index c1aa066ae1b0..17fb451e27c5 100644
--- a/arch/arm/mach-tegra/board-p1852-sdhci.c
+++ b/arch/arm/mach-tegra/board-p1852-sdhci.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2010 Google, Inc.
*
- * Copyright (C) 2012 NVIDIA Corporation
+ * 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
@@ -35,9 +35,11 @@
#include "board-p1852.h"
#include "devices.h"
+#define P1852_SD1_CD TEGRA_GPIO_PV2
+
static struct tegra_sdhci_platform_data tegra_sdhci_platform_data1 = {
- .cd_gpio = TEGRA_GPIO_PV2,
- .wp_gpio = TEGRA_GPIO_PD3,
+ .cd_gpio = P1852_SD1_CD,
+ .wp_gpio = -1,
.power_gpio = -1,
.is_8bit = false,
};
@@ -49,13 +51,6 @@ static struct tegra_sdhci_platform_data tegra_sdhci_platform_data2 = {
.is_8bit = true,
};
-static struct tegra_sdhci_platform_data tegra_sdhci_platform_data3 = {
- .cd_gpio = TEGRA_GPIO_PV3,
- .wp_gpio = TEGRA_GPIO_PD4,
- .power_gpio = -1,
- .is_8bit = false,
-};
-
static struct tegra_sdhci_platform_data tegra_sdhci_platform_data4 = {
.cd_gpio = -1,
.wp_gpio = -1,
@@ -67,12 +62,10 @@ int __init p1852_sdhci_init(void)
{
tegra_sdhci_device1.dev.platform_data = &tegra_sdhci_platform_data1;
tegra_sdhci_device2.dev.platform_data = &tegra_sdhci_platform_data2;
- tegra_sdhci_device3.dev.platform_data = &tegra_sdhci_platform_data3;
tegra_sdhci_device4.dev.platform_data = &tegra_sdhci_platform_data4;
platform_device_register(&tegra_sdhci_device1);
platform_device_register(&tegra_sdhci_device2);
- platform_device_register(&tegra_sdhci_device3);
platform_device_register(&tegra_sdhci_device4);
return 0;
diff --git a/arch/arm/mach-tegra/board-p1852.c b/arch/arm/mach-tegra/board-p1852.c
index 020671a7513b..ce7768e19594 100644
--- a/arch/arm/mach-tegra/board-p1852.c
+++ b/arch/arm/mach-tegra/board-p1852.c
@@ -35,6 +35,9 @@
#include <linux/platform_data/tegra_nor.h>
#include <linux/spi/spi.h>
#include <linux/mtd/partitions.h>
+#if defined(CONFIG_TOUCHSCREEN_ATMEL_MXT)
+#include <linux/i2c/atmel_mxt_ts.h>
+#endif
#include <mach/clk.h>
#include <mach/iomap.h>
#include <mach/irqs.h>
@@ -48,6 +51,7 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <mach/usb_phy.h>
+#include <mach/tegra_fiq_debugger.h>
#include <sound/wm8903.h>
#include <mach/tsensor.h>
#include "board.h"
@@ -57,42 +61,6 @@
#include "gpio-names.h"
#include "fuse.h"
-static struct tegra_utmip_config utmi_phy_config[] = {
- [0] = {
- .hssync_start_delay = 0,
- .idle_wait_delay = 17,
- .elastic_limit = 16,
- .term_range_adj = 6,
- .xcvr_setup = 15,
- .xcvr_setup_offset = 0,
- .xcvr_use_fuses = 1,
- .xcvr_lsfslew = 2,
- .xcvr_lsrslew = 2,
- },
- [1] = {
- .hssync_start_delay = 0,
- .idle_wait_delay = 17,
- .elastic_limit = 16,
- .term_range_adj = 6,
- .xcvr_setup = 15,
- .xcvr_setup_offset = 0,
- .xcvr_use_fuses = 1,
- .xcvr_lsfslew = 2,
- .xcvr_lsrslew = 2,
- },
- [2] = {
- .hssync_start_delay = 0,
- .idle_wait_delay = 17,
- .elastic_limit = 16,
- .term_range_adj = 6,
- .xcvr_setup = 8,
- .xcvr_setup_offset = 0,
- .xcvr_use_fuses = 1,
- .xcvr_lsfslew = 2,
- .xcvr_lsrslew = 2,
- },
-};
-
static __initdata struct tegra_clk_init_table p1852_clk_init_table[] = {
/* name parent rate enabled */
{ "pll_m", NULL, 0, true},
@@ -101,9 +69,10 @@ static __initdata struct tegra_clk_init_table p1852_clk_init_table[] = {
{ "pwm", "clk_32k", 32768, false},
{ "blink", "clk_32k", 32768, true},
{ "pll_a", NULL, 552960000, false},
- { "pll_a_out0", NULL, 12288000, false},
- { "d_audio", "pll_a_out0", 12288000, false},
- { "nor", "pll_p", 86500000, true},
+ /* audio cif clock should be faster than i2s */
+ { "pll_a_out0", NULL, 24576000, false},
+ { "d_audio", "pll_a_out0", 24576000, false},
+ { "nor", "pll_p", 102000000, true},
{ "uarta", "pll_p", 480000000, true},
{ "uartd", "pll_p", 480000000, true},
{ "uarte", "pll_p", 480000000, true},
@@ -115,16 +84,11 @@ static __initdata struct tegra_clk_init_table p1852_clk_init_table[] = {
{ "sbc5", "pll_m", 100000000, true},
{ "sbc6", "pll_m", 100000000, true},
{ "cpu_g", "cclk_g", 900000000, true},
- { "i2s0", "pll_a_out0", 12288000, false},
- { "i2s1", "pll_a_out0", 12288000, false},
- { "i2s2", "pll_a_out0", 12288000, false},
- { "i2s3", "pll_a_out0", 12288000, false},
- { "i2s4", "pll_a_out0", 12288000, false},
- { "audio0", "i2s0_sync", 12288000, false},
- { "audio1", "i2s1_sync", 12288000, false},
- { "audio2", "i2s2_sync", 12288000, false},
- { "audio3", "i2s3_sync", 12288000, false},
- { "audio4", "i2s4_sync", 12288000, false},
+ { "i2s0", "pll_a_out0", 24576000, false},
+ { "i2s1", "pll_a_out0", 24576000, false},
+ { "i2s2", "pll_a_out0", 24576000, false},
+ { "i2s3", "pll_a_out0", 24576000, false},
+ { "i2s4", "pll_a_out0", 24576000, false},
{ "apbif", "clk_m", 12000000, false},
{ "dam0", "clk_m", 12000000, true},
{ "dam1", "clk_m", 12000000, true},
@@ -141,6 +105,7 @@ static __initdata struct tegra_clk_init_table p1852_clk_init_table[] = {
{ "i2c4", "pll_p", 3200000, true},
{ "i2c5", "pll_p", 3200000, true},
{ "sdmmc2", "pll_p", 104000000, false},
+ {"wake.sclk", NULL, 334000000, true },
{ NULL, NULL, 0, 0},
};
@@ -234,26 +199,57 @@ static void __init p1852_uart_init(void)
ARRAY_SIZE(p1852_uart_devices));
}
-static struct tegra_p1852_platform_data p1852_audio_pdata = {
+#if defined(CONFIG_TEGRA_P1852_TDM)
+static struct tegra_p1852_platform_data p1852_audio_tdm_pdata = {
+ .codec_info[0] = {
+ .codec_dai_name = "dit-hifi",
+ .cpu_dai_name = "tegra30-i2s.0",
+ .codec_name = "spdif-dit.0",
+ .name = "tegra-i2s-1",
+ .pcm_driver = "tegra-tdm-pcm-audio",
+ .i2s_format = format_tdm,
+ .master = 1,
+ .num_slots = 4,
+ .slot_width = 32,
+ .tx_mask = 0x0f,
+ .rx_mask = 0x0f,
+ },
+ .codec_info[1] = {
+ .codec_dai_name = "dit-hifi",
+ .cpu_dai_name = "tegra30-i2s.4",
+ .codec_name = "spdif-dit.1",
+ .name = "tegra-i2s-2",
+ .pcm_driver = "tegra-tdm-pcm-audio",
+ .i2s_format = format_tdm,
+ .master = 1,
+ .num_slots = 8,
+ .slot_width = 32,
+ .tx_mask = 0xff,
+ .rx_mask = 0xff,
+ },
+};
+#else
+static struct tegra_p1852_platform_data p1852_audio_i2s_pdata = {
.codec_info[0] = {
.codec_dai_name = "dit-hifi",
.cpu_dai_name = "tegra30-i2s.0",
.codec_name = "spdif-dit.0",
.name = "tegra-i2s-1",
+ .pcm_driver = "tegra-pcm-audio",
.i2s_format = format_i2s,
.master = 1,
},
.codec_info[1] = {
.codec_dai_name = "dit-hifi",
- .cpu_dai_name = "tegra30-i2s.1",
+ .cpu_dai_name = "tegra30-i2s.4",
.codec_name = "spdif-dit.1",
.name = "tegra-i2s-2",
+ .pcm_driver = "tegra-pcm-audio",
.i2s_format = format_i2s,
.master = 0,
},
-
};
-
+#endif
static struct platform_device generic_codec_1 = {
.name = "spdif-dit",
.id = 0,
@@ -267,17 +263,22 @@ static struct platform_device tegra_snd_p1852 = {
.name = "tegra-snd-p1852",
.id = 0,
.dev = {
- .platform_data = &p1852_audio_pdata,
+#if defined(CONFIG_TEGRA_P1852_TDM)
+ .platform_data = &p1852_audio_tdm_pdata,
+#else
+ .platform_data = &p1852_audio_i2s_pdata,
+#endif
},
};
static void p1852_i2s_audio_init(void)
{
platform_device_register(&tegra_pcm_device);
+ platform_device_register(&tegra_tdm_pcm_device);
platform_device_register(&generic_codec_1);
platform_device_register(&generic_codec_2);
platform_device_register(&tegra_i2s_device0);
- platform_device_register(&tegra_i2s_device1);
+ platform_device_register(&tegra_i2s_device4);
platform_device_register(&tegra_ahub_device);
platform_device_register(&tegra_snd_p1852);
}
@@ -305,6 +306,15 @@ static struct spi_board_info tegra_spi_devices[] __initdata = {
},
{
.modalias = "spidev",
+ .bus_num = 2,
+ .chip_select = 0,
+ .mode = SPI_MODE_0,
+ .max_speed_hz = 18000000,
+ .platform_data = NULL,
+ .irq = 0,
+ },
+ {
+ .modalias = "spidev",
.bus_num = 3,
.chip_select = 1,
.mode = SPI_MODE_0,
@@ -329,69 +339,222 @@ static void p1852_spi_init(void)
tegra_spi_device2.name = "spi_slave_tegra";
platform_device_register(&tegra_spi_device1);
platform_device_register(&tegra_spi_device2);
+ platform_device_register(&tegra_spi_device3);
p852_register_spidev();
}
+static struct platform_device tegra_camera = {
+ .name = "tegra_camera",
+ .id = -1,
+};
+
static struct platform_device *p1852_devices[] __initdata = {
-#if defined(CONFIG_TEGRA_IOVMM_SMMU)
+#if defined(CONFIG_TEGRA_IOVMM_SMMU) || defined(CONFIG_TEGRA_IOMMU_SMMU)
&tegra_smmu_device,
#endif
#if defined(CONFIG_TEGRA_AVP)
&tegra_avp_device,
#endif
- &tegra_wdt_device
+ &tegra_camera,
+ &tegra_wdt0_device,
+ &tegra_wdt1_device,
+ &tegra_wdt2_device
};
-static struct usb_phy_plat_data tegra_usb_phy_pdata[] = {
- [0] = {
- .instance = 0,
- .vbus_gpio = -1,
- .vbus_reg_supply = NULL,
- },
- [1] = {
- .instance = 1,
- .vbus_gpio = -1,
+
+#ifdef CONFIG_TOUCHSCREEN_ATMEL_MXT
+
+#define MXT_CONFIG_CRC 0xD62DE8
+static const u8 config[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0x32, 0x0A, 0x00, 0x14, 0x14, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x00, 0x00,
+ 0x1B, 0x2A, 0x00, 0x20, 0x3C, 0x04, 0x05, 0x00,
+ 0x02, 0x01, 0x00, 0x0A, 0x0A, 0x0A, 0x0A, 0xFF,
+ 0x02, 0x55, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x64, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23,
+ 0x00, 0x00, 0x00, 0x05, 0x0A, 0x15, 0x1E, 0x00,
+ 0x00, 0x04, 0xFF, 0x03, 0x3F, 0x64, 0x64, 0x01,
+ 0x0A, 0x14, 0x28, 0x4B, 0x00, 0x02, 0x00, 0x64,
+ 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x10, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+#define MXT_CONFIG_CRC_SKU2000 0xA24D9A
+static const u8 config_sku2000[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0x32, 0x0A, 0x00, 0x14, 0x14, 0x19,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x00, 0x00,
+ 0x1B, 0x2A, 0x00, 0x20, 0x3A, 0x04, 0x05, 0x00, //23=thr 2 di
+ 0x04, 0x04, 0x41, 0x0A, 0x0A, 0x0A, 0x0A, 0xFF,
+ 0x02, 0x55, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, //0A=limit
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23,
+ 0x00, 0x00, 0x00, 0x05, 0x0A, 0x15, 0x1E, 0x00,
+ 0x00, 0x04, 0x00, 0x03, 0x3F, 0x64, 0x64, 0x01,
+ 0x0A, 0x14, 0x28, 0x4B, 0x00, 0x02, 0x00, 0x64,
+ 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x10, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static struct mxt_platform_data atmel_mxt_info = {
+ .x_line = 27,
+ .y_line = 42,
+ .x_size = 768,
+ .y_size = 1366,
+ .blen = 0x20,
+ .threshold = 0x3C,
+ .voltage = 3300000, /* 3.3V */
+ .orient = 5,
+ .config = config,
+ .config_length = 157,
+ .config_crc = MXT_CONFIG_CRC,
+ .irqflags = IRQF_TRIGGER_FALLING,
+/* .read_chg = &read_chg, */
+ .read_chg = NULL,
+};
+
+static struct i2c_board_info __initdata atmel_i2c_info[] = {
+ {
+ I2C_BOARD_INFO("atmel_mxt_ts", 0x5A),
+ .irq = TEGRA_GPIO_TO_IRQ(TOUCH_GPIO_IRQ_ATMEL_T9),
+ .platform_data = &atmel_mxt_info,
+ }
+};
+
+static __initdata struct tegra_clk_init_table spi_clk_init_table[] = {
+ /* name parent rate enabled */
+ { "sbc1", "pll_p", 52000000, true},
+ { NULL, NULL, 0, 0},
+};
+
+static int __init p1852_touch_init(void)
+{
+ tegra_gpio_enable(TOUCH_GPIO_IRQ_ATMEL_T9);
+ tegra_gpio_enable(TOUCH_GPIO_RST_ATMEL_T9);
+
+ gpio_request(TOUCH_GPIO_IRQ_ATMEL_T9, "atmel-irq");
+ gpio_direction_input(TOUCH_GPIO_IRQ_ATMEL_T9);
+
+ gpio_request(TOUCH_GPIO_RST_ATMEL_T9, "atmel-reset");
+ gpio_direction_output(TOUCH_GPIO_RST_ATMEL_T9, 0);
+ msleep(1);
+ gpio_set_value(TOUCH_GPIO_RST_ATMEL_T9, 1);
+ msleep(100);
+
+ atmel_mxt_info.config = config_sku2000;
+ atmel_mxt_info.config_crc = MXT_CONFIG_CRC_SKU2000;
+
+ i2c_register_board_info(TOUCH_BUS_ATMEL_T9, atmel_i2c_info, 1);
+
+ return 0;
+}
+
+#endif // CONFIG_TOUCHSCREEN_ATMEL_MXT
+
+static struct tegra_usb_platform_data tegra_ehci1_utmi_pdata = {
+ .port_otg = false,
+ .has_hostpc = true,
+ .phy_intf = TEGRA_USB_PHY_INTF_UTMI,
+ .op_mode = TEGRA_USB_OPMODE_HOST,
+ .u_data.host = {
+ .vbus_gpio = -1,
+ .vbus_reg = NULL,
+ .hot_plug = false,
+ .remote_wakeup_supported = true,
+ .power_off_on_suspend = true,
},
- [2] = {
- .instance = 2,
- .vbus_gpio = -1,
- .vbus_reg_supply = NULL,
+ .u_cfg.utmi = {
+ .hssync_start_delay = 0,
+ .idle_wait_delay = 17,
+ .elastic_limit = 16,
+ .term_range_adj = 6,
+ .xcvr_setup = 63,
+ .xcvr_setup_offset = 6,
+ .xcvr_use_fuses = 1,
+ .xcvr_lsfslew = 2,
+ .xcvr_lsrslew = 2,
+ .xcvr_use_lsb = 1,
},
};
-static struct tegra_ehci_platform_data tegra_ehci_pdata[] = {
- [0] = {
- .phy_config = &utmi_phy_config[0],
- .operating_mode = TEGRA_USB_HOST,
- .power_down_on_bus_suspend = 1,
+static struct tegra_usb_platform_data tegra_ehci2_utmi_pdata = {
+ .port_otg = false,
+ .has_hostpc = true,
+ .phy_intf = TEGRA_USB_PHY_INTF_UTMI,
+ .op_mode = TEGRA_USB_OPMODE_HOST,
+ .u_data.host = {
+ .vbus_gpio = -1,
+ .vbus_reg = NULL,
+ .hot_plug = false,
+ .remote_wakeup_supported = true,
+ .power_off_on_suspend = true,
},
- [1] = {
- .phy_config = &utmi_phy_config[1],
- .operating_mode = TEGRA_USB_HOST,
- .power_down_on_bus_suspend = 1,
+ .u_cfg.utmi = {
+ .hssync_start_delay = 0,
+ .idle_wait_delay = 17,
+ .elastic_limit = 16,
+ .term_range_adj = 6,
+ .xcvr_setup = 63,
+ .xcvr_setup_offset = 6,
+ .xcvr_use_fuses = 1,
+ .xcvr_lsfslew = 2,
+ .xcvr_lsrslew = 2,
+ .xcvr_use_lsb = 1,
+ },
+};
+
+static struct tegra_usb_platform_data tegra_ehci3_utmi_pdata = {
+ .port_otg = false,
+ .has_hostpc = true,
+ .phy_intf = TEGRA_USB_PHY_INTF_UTMI,
+ .op_mode = TEGRA_USB_OPMODE_HOST,
+ .u_data.host = {
+ .vbus_gpio = -1,
+ .vbus_reg = NULL,
+ .hot_plug = false,
+ .remote_wakeup_supported = true,
+ .power_off_on_suspend = true,
},
- [2] = {
- .phy_config = &utmi_phy_config[2],
- .operating_mode = TEGRA_USB_HOST,
- .power_down_on_bus_suspend = 1,
+ .u_cfg.utmi = {
+ .hssync_start_delay = 0,
+ .idle_wait_delay = 17,
+ .elastic_limit = 16,
+ .term_range_adj = 6,
+ .xcvr_setup = 63,
+ .xcvr_setup_offset = 6,
+ .xcvr_use_fuses = 1,
+ .xcvr_lsfslew = 2,
+ .xcvr_lsrslew = 2,
+ .xcvr_use_lsb = 1,
},
};
static void p1852_usb_init(void)
{
- /* Need to parse sku info to decide host/device mode */
- tegra_usb_phy_init(tegra_usb_phy_pdata,
- ARRAY_SIZE(tegra_usb_phy_pdata));
-
- tegra_ehci1_device.dev.platform_data = &tegra_ehci_pdata[0];
+ tegra_ehci1_device.dev.platform_data = &tegra_ehci1_utmi_pdata;
platform_device_register(&tegra_ehci1_device);
- tegra_ehci2_device.dev.platform_data = &tegra_ehci_pdata[1];
+ tegra_ehci2_device.dev.platform_data = &tegra_ehci2_utmi_pdata;
platform_device_register(&tegra_ehci2_device);
- tegra_ehci3_device.dev.platform_data = &tegra_ehci_pdata[2];
+ tegra_ehci3_device.dev.platform_data = &tegra_ehci3_utmi_pdata;
platform_device_register(&tegra_ehci3_device);
-
}
static struct tegra_nor_platform_data p1852_nor_data = {
@@ -402,12 +565,12 @@ static struct tegra_nor_platform_data p1852_nor_data = {
.chip_parms = {
/* FIXME: Need to use characterized value */
.timing_default = {
- .timing0 = 0xA0400273,
- .timing1 = 0x00030402,
+ .timing0 = 0x30300263,
+ .timing1 = 0x00030302,
},
.timing_read = {
- .timing0 = 0xA0400273,
- .timing1 = 0x00030402,
+ .timing0 = 0x30300263,
+ .timing1 = 0x00030302,
},
},
};
@@ -432,9 +595,13 @@ static void __init tegra_p1852_init(void)
p1852_sdhci_init();
p1852_spi_init();
platform_add_devices(p1852_devices, ARRAY_SIZE(p1852_devices));
+#ifdef CONFIG_TOUCHSCREEN_ATMEL_MXT
+ p1852_touch_init();
+#endif
p1852_panel_init();
p1852_nor_init();
p1852_pcie_init();
+ tegra_serial_debug_init(TEGRA_UARTD_BASE, INT_WDT_CPU, NULL, -1, -1);
}
static void __init tegra_p1852_reserve(void)
diff --git a/arch/arm/mach-tegra/board-p1852.h b/arch/arm/mach-tegra/board-p1852.h
index f146f30ed2c5..1ac0968f9518 100644
--- a/arch/arm/mach-tegra/board-p1852.h
+++ b/arch/arm/mach-tegra/board-p1852.h
@@ -96,4 +96,10 @@ int p1852_panel_init(void);
int p1852_gpio_init(void);
int p1852_pins_state_init(void);
+#ifdef CONFIG_TOUCHSCREEN_ATMEL_MXT
+#define TOUCH_GPIO_IRQ_ATMEL_T9 TEGRA_GPIO_PEE1
+#define TOUCH_GPIO_RST_ATMEL_T9 TEGRA_GPIO_PW2
+#define TOUCH_BUS_ATMEL_T9 0
+#endif
+
#endif
diff --git a/arch/arm/mach-tegra/board-trimslice.c b/arch/arm/mach-tegra/board-trimslice.c
index 823060ec478f..626cd1b34114 100644
--- a/arch/arm/mach-tegra/board-trimslice.c
+++ b/arch/arm/mach-tegra/board-trimslice.c
@@ -6,6 +6,7 @@
*
* Based on board-harmony.c
* Copyright (C) 2010 Google, Inc.
+ * Copyright (C) 2011-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
@@ -95,7 +96,7 @@ static struct platform_device *trimslice_devices[] __initdata = {
&tegra_das_device,
&tegra_pcm_device,
&trimslice_audio_device,
- &trimslice_pci_platform_data,
+ &tegra_pci_device,
};
static struct i2c_board_info trimslice_i2c3_board_info[] = {
diff --git a/arch/arm/mach-tegra/board-ventana-panel.c b/arch/arm/mach-tegra/board-ventana-panel.c
index d7f607a7ad1b..56a222432fe0 100644
--- a/arch/arm/mach-tegra/board-ventana-panel.c
+++ b/arch/arm/mach-tegra/board-ventana-panel.c
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/board-ventana-panel.c
*
- * Copyright (c) 2010-2012, 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
@@ -27,7 +27,7 @@
#include <linux/earlysuspend.h>
#include <linux/pwm_backlight.h>
#include <linux/nvhost.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include <mach/irqs.h>
#include <mach/iomap.h>
#include <mach/dc.h>
@@ -36,6 +36,7 @@
#include "devices.h"
#include "gpio-names.h"
#include "board.h"
+#include "tegra2_host1x_devices.h"
#define ventana_bl_enb TEGRA_GPIO_PD4
#define ventana_lvds_shutdown TEGRA_GPIO_PB2
@@ -63,8 +64,6 @@ static int ventana_backlight_init(struct device *dev) {
ret = gpio_direction_output(ventana_bl_enb, 1);
if (ret < 0)
gpio_free(ventana_bl_enb);
- else
- tegra_gpio_enable(ventana_bl_enb);
return ret;
};
@@ -72,7 +71,6 @@ static int ventana_backlight_init(struct device *dev) {
static void ventana_backlight_exit(struct device *dev) {
gpio_set_value(ventana_bl_enb, 0);
gpio_free(ventana_bl_enb);
- tegra_gpio_disable(ventana_bl_enb);
}
static int ventana_backlight_notify(struct device *unused, int brightness)
@@ -284,7 +282,7 @@ static struct tegra_dc_platform_data ventana_disp1_pdata = {
};
static struct tegra_dc_platform_data ventana_disp2_pdata = {
- .flags = 0,
+ .flags = TEGRA_DC_FLAG_ENABLED,
.default_out = &ventana_disp2_out,
.fb = &ventana_hdmi_fb_data,
};
@@ -349,6 +347,8 @@ static struct platform_device *ventana_gfx_devices[] __initdata = {
&ventana_nvmap_device,
#endif
&tegra_pwfm2_device,
+};
+static struct platform_device *ventana_backlight_devices[] __initdata = {
&ventana_backlight_device,
};
@@ -366,16 +366,8 @@ static void ventana_panel_early_suspend(struct early_suspend *h)
if (num_registered_fb > 1)
fb_blank(registered_fb[1], FB_BLANK_NORMAL);
#ifdef CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND
- cpufreq_save_default_governor();
- cpufreq_set_conservative_governor();
- cpufreq_set_conservative_governor_param("up_threshold",
- SET_CONSERVATIVE_GOVERNOR_UP_THRESHOLD);
-
- cpufreq_set_conservative_governor_param("down_threshold",
- SET_CONSERVATIVE_GOVERNOR_DOWN_THRESHOLD);
-
- cpufreq_set_conservative_governor_param("freq_step",
- SET_CONSERVATIVE_GOVERNOR_FREQ_STEP);
+ cpufreq_store_default_gov();
+ cpufreq_change_gov(cpufreq_conservative_gov);
#endif
}
@@ -383,7 +375,7 @@ static void ventana_panel_late_resume(struct early_suspend *h)
{
unsigned i;
#ifdef CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND
- cpufreq_restore_default_governor();
+ cpufreq_restore_default_gov();
#endif
for (i = 0; i < num_registered_fb; i++)
fb_blank(registered_fb[i], FB_BLANK_UNBLANK);
@@ -397,13 +389,10 @@ int __init ventana_panel_init(void)
gpio_request(ventana_lvds_shutdown, "lvds_shdn");
gpio_direction_output(ventana_lvds_shutdown, 1);
- tegra_gpio_enable(ventana_lvds_shutdown);
- tegra_gpio_enable(ventana_hdmi_enb);
gpio_request(ventana_hdmi_enb, "hdmi_5v_en");
gpio_direction_output(ventana_hdmi_enb, 1);
- tegra_gpio_enable(ventana_hdmi_hpd);
gpio_request(ventana_hdmi_hpd, "hdmi_hpd");
gpio_direction_input(ventana_hdmi_hpd);
@@ -420,7 +409,7 @@ int __init ventana_panel_init(void)
#endif
#ifdef CONFIG_TEGRA_GRHOST
- err = nvhost_device_register(&tegra_grhost_device);
+ err = tegra2_register_host1x_devices();
if (err)
return err;
#endif
@@ -457,6 +446,9 @@ int __init ventana_panel_init(void)
err = nvhost_device_register(&ventana_disp2_device);
#endif
+ err = platform_add_devices(ventana_backlight_devices,
+ ARRAY_SIZE(ventana_backlight_devices));
+
return err;
}
diff --git a/arch/arm/mach-tegra/board-ventana-pinmux.c b/arch/arm/mach-tegra/board-ventana-pinmux.c
index 9f3447264599..eb371384ed4c 100644
--- a/arch/arm/mach-tegra/board-ventana-pinmux.c
+++ b/arch/arm/mach-tegra/board-ventana-pinmux.c
@@ -47,11 +47,11 @@
}
static __initdata struct tegra_drive_pingroup_config ventana_drive_pinmux[] = {
- DEFAULT_DRIVE(DDC),
DEFAULT_DRIVE(VI1),
DEFAULT_DRIVE(SDIO1),
SET_DRIVE(DBG, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST),
+ SET_DRIVE(DDC, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST),
SET_DRIVE(VI2, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST),
SET_DRIVE(AT1, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST),
SET_DRIVE(AO1, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST),
@@ -126,7 +126,7 @@ static __initdata struct tegra_pingroup_config ventana_pinmux[] = {
{TEGRA_PINGROUP_LPP, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_LPW0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_LPW1, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LPW2, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_LPW2, TEGRA_MUX_DISPLAYB, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_LSC0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_LSC1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_LSCK, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
diff --git a/arch/arm/mach-tegra/board-ventana-power.c b/arch/arm/mach-tegra/board-ventana-power.c
index 2acfdfed28e4..aa6f4be203ad 100644
--- a/arch/arm/mach-tegra/board-ventana-power.c
+++ b/arch/arm/mach-tegra/board-ventana-power.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2012 NVIDIA, Inc.
+ * 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 version 2 as
@@ -34,7 +34,6 @@
#include "gpio-names.h"
#include "fuse.h"
#include "pm.h"
-#include "wakeups-t2.h"
#include "board.h"
#include "board-ventana.h"
@@ -47,7 +46,6 @@ int __init ventana_charge_init(void)
{
gpio_request(CHARGING_DISABLE, "chg_disable");
gpio_direction_output(CHARGING_DISABLE, 0);
- tegra_gpio_enable(CHARGING_DISABLE);
return 0;
}
@@ -255,14 +253,6 @@ static struct platform_device *fixed_voltage_regulators[] __initdata = {
int __init ventana_fixed_voltage_regulator_init(void)
{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(fixed_voltage_regulators); ++i) {
- struct fixed_voltage_config *fixed_voltage_regulators_pdata =
- fixed_voltage_regulators[i]->dev.platform_data;
- if (fixed_voltage_regulators_pdata->gpio < TEGRA_NR_GPIOS)
- tegra_gpio_enable(fixed_voltage_regulators_pdata->gpio);
- }
return platform_add_devices(fixed_voltage_regulators,
ARRAY_SIZE(fixed_voltage_regulators));
}
@@ -317,7 +307,6 @@ static struct platform_device ventana_charger_device = {
int __init ventana_charger_init(void)
{
- tegra_gpio_enable(AC_PRESENT_GPIO);
platform_device_register(&ventana_charger_device);
return 0;
}
diff --git a/arch/arm/mach-tegra/board-ventana-sdhci.c b/arch/arm/mach-tegra/board-ventana-sdhci.c
index 188335ac98c5..9d426aadff79 100644
--- a/arch/arm/mach-tegra/board-ventana-sdhci.c
+++ b/arch/arm/mach-tegra/board-ventana-sdhci.c
@@ -1,7 +1,6 @@
/*
- * arch/arm/mach-tegra/board-harmony-sdhci.c
- *
* Copyright (C) 2010 Google, Inc.
+ * 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
@@ -132,6 +131,7 @@ static struct tegra_sdhci_platform_data tegra_sdhci_platform_data0 = {
.embedded_sdio = &embedded_sdio_data0,
#endif
.built_in = 0,
+ .ocr_mask = MMC_OCR_1V8_MASK,
},
#ifndef CONFIG_MMC_EMBEDDED_SDIO
.pm_flags = MMC_PM_KEEP_POWER,
@@ -257,10 +257,6 @@ static int __init ventana_wifi_init(void)
gpio_request(VENTANA_WLAN_RST, "wlan_rst");
gpio_request(VENTANA_WLAN_WOW, "bcmsdh_sdmmc");
- tegra_gpio_enable(VENTANA_WLAN_PWR);
- tegra_gpio_enable(VENTANA_WLAN_RST);
- tegra_gpio_enable(VENTANA_WLAN_WOW);
-
gpio_direction_output(VENTANA_WLAN_PWR, 0);
gpio_direction_output(VENTANA_WLAN_RST, 0);
gpio_direction_input(VENTANA_WLAN_WOW);
@@ -274,11 +270,6 @@ static int __init ventana_wifi_init(void)
}
int __init ventana_sdhci_init(void)
{
- tegra_gpio_enable(tegra_sdhci_platform_data2.power_gpio);
- tegra_gpio_enable(tegra_sdhci_platform_data2.cd_gpio);
- tegra_gpio_enable(tegra_sdhci_platform_data2.wp_gpio);
- tegra_gpio_enable(tegra_sdhci_platform_data3.power_gpio);
-
platform_device_register(&tegra_sdhci_device3);
platform_device_register(&tegra_sdhci_device2);
platform_device_register(&tegra_sdhci_device0);
diff --git a/arch/arm/mach-tegra/board-ventana-sensors.c b/arch/arm/mach-tegra/board-ventana-sensors.c
index 574bdb25fc2a..db6ebfd2e137 100644
--- a/arch/arm/mach-tegra/board-ventana-sensors.c
+++ b/arch/arm/mach-tegra/board-ventana-sensors.c
@@ -186,7 +186,6 @@ static struct ssl3250a_platform_data ventana_ssl3250a_pdata = {
static void ventana_isl29018_init(void)
{
- tegra_gpio_enable(ISL29018_IRQ_GPIO);
gpio_request(ISL29018_IRQ_GPIO, "isl29018");
gpio_direction_input(ISL29018_IRQ_GPIO);
}
@@ -194,7 +193,6 @@ static void ventana_isl29018_init(void)
#ifdef CONFIG_SENSORS_AK8975
static void ventana_akm8975_init(void)
{
- tegra_gpio_enable(AKM8975_IRQ_GPIO);
gpio_request(AKM8975_IRQ_GPIO, "akm8975");
gpio_direction_input(AKM8975_IRQ_GPIO);
}
@@ -202,21 +200,118 @@ static void ventana_akm8975_init(void)
static void ventana_nct1008_init(void)
{
- tegra_gpio_enable(NCT1008_THERM2_GPIO);
gpio_request(NCT1008_THERM2_GPIO, "temp_alert");
gpio_direction_input(NCT1008_THERM2_GPIO);
}
+static long ventana_shutdown_temp = 115000;
+static long ventana_throttle_temp = 90000;
+static long ventana_throttle_hysteresis = 3000;
+static struct nct1008_data *nct_data;
+
+static void ventana_thermal_alert(void *vdata)
+{
+ struct nct1008_data *data = vdata;
+ long temp;
+ long lo_limit, hi_limit;
+ bool is_above_throttle;
+
+ nct1008_thermal_get_temp(data, &temp);
+ is_above_throttle = (temp >= ventana_throttle_temp);
+
+ if (is_above_throttle != tegra_is_throttling())
+ tegra_throttling_enable(is_above_throttle);
+
+ if (is_above_throttle) {
+ lo_limit = ventana_throttle_temp - ventana_throttle_hysteresis;
+ hi_limit = ventana_shutdown_temp;
+ } else {
+ lo_limit = 0;
+ hi_limit = ventana_throttle_temp;
+ }
+
+ nct1008_thermal_set_limits(data, lo_limit, hi_limit);
+}
+
+static void nct1008_probe_callback(struct nct1008_data *data)
+{
+ nct_data = data;
+ nct1008_thermal_set_shutdown_temp(data, ventana_shutdown_temp);
+ nct1008_thermal_set_alert(data, ventana_thermal_alert, data);
+ nct1008_thermal_set_limits(data, 0, ventana_throttle_temp);
+}
+
+#ifdef CONFIG_DEBUG_FS
+static int ventana_thermal_get_throttle_temp(void *data, u64 *val)
+{
+ *val = (u64)ventana_throttle_temp;
+ return 0;
+}
+
+static int ventana_thermal_set_throttle_temp(void *data, u64 val)
+{
+ ventana_throttle_temp = val;
+ if (nct_data)
+ ventana_thermal_alert(nct_data);
+
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(throttle_fops,
+ ventana_thermal_get_throttle_temp,
+ ventana_thermal_set_throttle_temp,
+ "%llu\n");
+
+static int ventana_thermal_get_shutdown_temp(void *data, u64 *val)
+{
+ *val = (u64)ventana_shutdown_temp;
+ return 0;
+}
+
+static int ventana_thermal_set_shutdown_temp(void *data, u64 val)
+{
+ ventana_shutdown_temp = val;
+ if (nct_data)
+ nct1008_thermal_set_shutdown_temp(nct_data,
+ ventana_shutdown_temp);
+
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(shutdown_fops,
+ ventana_thermal_get_shutdown_temp,
+ ventana_thermal_set_shutdown_temp,
+ "%llu\n");
+
+
+static int __init ventana_thermal_debug_init(void)
+{
+ struct dentry *thermal_debugfs_root;
+
+ thermal_debugfs_root = debugfs_create_dir("thermal", 0);
+
+ if (!debugfs_create_file("throttle", 0644, thermal_debugfs_root,
+ NULL, &throttle_fops))
+ return -ENOMEM;
+
+ if (!debugfs_create_file("shutdown", 0644, thermal_debugfs_root,
+ NULL, &shutdown_fops))
+ return -ENOMEM;
+
+ return 0;
+}
+
+late_initcall(ventana_thermal_debug_init);
+
+#endif
+
+
static struct nct1008_platform_data ventana_nct1008_pdata = {
.supported_hwrev = true,
.ext_range = false,
.conv_rate = 0x08,
.offset = 0,
- .hysteresis = 0,
- .shutdown_ext_limit = 115,
- .shutdown_local_limit = 120,
- .throttling_ext_limit = 90,
- .alarm_fn = tegra_throttling_enable,
+ .probe_callback = nct1008_probe_callback,
};
static const struct i2c_board_info ventana_i2c0_board_info[] = {
@@ -379,7 +474,6 @@ static void mpuirq_init(void)
#if (MPU_GYRO_TYPE == MPU_TYPE_MPU3050)
#if MPU_ACCEL_IRQ_GPIO
/* ACCEL-IRQ assignment */
- tegra_gpio_enable(MPU_ACCEL_IRQ_GPIO);
ret = gpio_request(MPU_ACCEL_IRQ_GPIO, MPU_ACCEL_NAME);
if (ret < 0) {
pr_err("%s: gpio_request failed %d\n", __func__, ret);
@@ -396,7 +490,6 @@ static void mpuirq_init(void)
#endif
/* MPU-IRQ assignment */
- tegra_gpio_enable(MPU_GYRO_IRQ_GPIO);
ret = gpio_request(MPU_GYRO_IRQ_GPIO, MPU_GYRO_NAME);
if (ret < 0) {
pr_err("%s: gpio_request failed %d\n", __func__, ret);
@@ -465,37 +558,35 @@ int __init ventana_sensors_init(void)
struct tegra_camera_gpios {
const char *name;
int gpio;
- bool tegra_internal_gpio;
int enabled;
};
-#define TEGRA_CAMERA_GPIO(_name, _gpio, _tegra_internal_gpio, _enabled) \
+#define TEGRA_CAMERA_GPIO(_name, _gpio, _enabled) \
{ \
.name = _name, \
.gpio = _gpio, \
- .tegra_internal_gpio = _tegra_internal_gpio, \
.enabled = _enabled, \
}
static struct tegra_camera_gpios ventana_camera_gpio_keys[] = {
- [0] = TEGRA_CAMERA_GPIO("camera_power_en", CAMERA_POWER_GPIO, true, 1),
- [1] = TEGRA_CAMERA_GPIO("camera_csi_sel", CAMERA_CSI_MUX_SEL_GPIO, true, 0),
- [2] = TEGRA_CAMERA_GPIO("torch_gpio_act", CAMERA_FLASH_ACT_GPIO, true, 0),
+ [0] = TEGRA_CAMERA_GPIO("camera_power_en", CAMERA_POWER_GPIO, 1),
+ [1] = TEGRA_CAMERA_GPIO("camera_csi_sel", CAMERA_CSI_MUX_SEL_GPIO, 0),
+ [2] = TEGRA_CAMERA_GPIO("torch_gpio_act", CAMERA_FLASH_ACT_GPIO, 0),
- [3] = TEGRA_CAMERA_GPIO("en_avdd_csi", AVDD_DSI_CSI_ENB_GPIO, false, 1),
- [4] = TEGRA_CAMERA_GPIO("cam_i2c_mux_rst_lo", CAM_I2C_MUX_RST_GPIO, false, 1),
+ [3] = TEGRA_CAMERA_GPIO("en_avdd_csi", AVDD_DSI_CSI_ENB_GPIO, 1),
+ [4] = TEGRA_CAMERA_GPIO("cam_i2c_mux_rst_lo", CAM_I2C_MUX_RST_GPIO, 1),
- [5] = TEGRA_CAMERA_GPIO("cam2_af_pwdn_lo", CAM2_AF_PWR_DN_L_GPIO, false, 0),
- [6] = TEGRA_CAMERA_GPIO("cam2_pwdn", CAM2_PWR_DN_GPIO, false, 0),
- [7] = TEGRA_CAMERA_GPIO("cam2_rst_lo", CAM2_RST_L_GPIO, false, 1),
+ [5] = TEGRA_CAMERA_GPIO("cam2_af_pwdn_lo", CAM2_AF_PWR_DN_L_GPIO, 0),
+ [6] = TEGRA_CAMERA_GPIO("cam2_pwdn", CAM2_PWR_DN_GPIO, 0),
+ [7] = TEGRA_CAMERA_GPIO("cam2_rst_lo", CAM2_RST_L_GPIO, 1),
- [8] = TEGRA_CAMERA_GPIO("cam3_af_pwdn_lo", CAM3_AF_PWR_DN_L_GPIO, false, 0),
- [9] = TEGRA_CAMERA_GPIO("cam3_pwdn", CAM3_PWR_DN_GPIO, false, 0),
- [10] = TEGRA_CAMERA_GPIO("cam3_rst_lo", CAM3_RST_L_GPIO, false, 1),
+ [8] = TEGRA_CAMERA_GPIO("cam3_af_pwdn_lo", CAM3_AF_PWR_DN_L_GPIO, 0),
+ [9] = TEGRA_CAMERA_GPIO("cam3_pwdn", CAM3_PWR_DN_GPIO, 0),
+ [10] = TEGRA_CAMERA_GPIO("cam3_rst_lo", CAM3_RST_L_GPIO, 1),
- [11] = TEGRA_CAMERA_GPIO("cam1_af_pwdn_lo", CAM1_AF_PWR_DN_L_GPIO, false, 0),
- [12] = TEGRA_CAMERA_GPIO("cam1_pwdn", CAM1_PWR_DN_GPIO, false, 0),
- [13] = TEGRA_CAMERA_GPIO("cam1_rst_lo", CAM1_RST_L_GPIO, false, 1),
+ [11] = TEGRA_CAMERA_GPIO("cam1_af_pwdn_lo", CAM1_AF_PWR_DN_L_GPIO, 0),
+ [12] = TEGRA_CAMERA_GPIO("cam1_pwdn", CAM1_PWR_DN_GPIO, 0),
+ [13] = TEGRA_CAMERA_GPIO("cam1_rst_lo", CAM1_RST_L_GPIO, 1),
};
int __init ventana_camera_late_init(void)
@@ -522,10 +613,6 @@ int __init ventana_camera_late_init(void)
i2c_new_device(i2c_get_adapter(3), ventana_i2c3_board_info_tca6416);
for (i = 0; i < ARRAY_SIZE(ventana_camera_gpio_keys); i++) {
-
- if (ventana_camera_gpio_keys[i].tegra_internal_gpio)
- tegra_gpio_enable(ventana_camera_gpio_keys[i].gpio);
-
ret = gpio_request(ventana_camera_gpio_keys[i].gpio,
ventana_camera_gpio_keys[i].name);
if (ret < 0) {
diff --git a/arch/arm/mach-tegra/board-ventana.c b/arch/arm/mach-tegra/board-ventana.c
index d371e720fdcf..c8c9ac49745f 100644
--- a/arch/arm/mach-tegra/board-ventana.c
+++ b/arch/arm/mach-tegra/board-ventana.c
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/board-ventana.c
*
- * Copyright (c) 2010-2011, NVIDIA Corporation.
+ * Copyright (c) 2010-2011 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
@@ -38,6 +38,7 @@
#include <linux/memblock.h>
#include <linux/i2c/atmel_mxt_ts.h>
#include <linux/tegra_uart.h>
+#include <linux/rfkill-gpio.h>
#include <sound/wm8903.h>
@@ -63,56 +64,28 @@
#include "wakeups-t2.h"
#include "pm.h"
-static struct tegra_utmip_config utmi_phy_config[] = {
- [0] = {
- .hssync_start_delay = 9,
- .idle_wait_delay = 17,
- .elastic_limit = 16,
- .term_range_adj = 6,
- .xcvr_setup = 15,
- .xcvr_setup_offset = 0,
- .xcvr_use_fuses = 1,
- .xcvr_lsfslew = 2,
- .xcvr_lsrslew = 2,
- },
- [1] = {
- .hssync_start_delay = 9,
- .idle_wait_delay = 17,
- .elastic_limit = 16,
- .term_range_adj = 6,
- .xcvr_setup = 8,
- .xcvr_setup_offset = 0,
- .xcvr_use_fuses = 1,
- .xcvr_lsfslew = 2,
- .xcvr_lsrslew = 2,
- },
-};
-
-static struct tegra_ulpi_config ulpi_phy_config = {
- .reset_gpio = TEGRA_GPIO_PG2,
- .clk = "cdev2",
-};
-static struct resource ventana_bcm4329_rfkill_resources[] = {
+static struct rfkill_gpio_platform_data ventana_bt_rfkill_pdata[] = {
{
- .name = "bcm4329_nshutdown_gpio",
- .start = TEGRA_GPIO_PU0,
- .end = TEGRA_GPIO_PU0,
- .flags = IORESOURCE_IO,
+ .name = "bt_rfkill",
+ .shutdown_gpio = TEGRA_GPIO_PU0,
+ .reset_gpio = TEGRA_GPIO_INVALID,
+ .type = RFKILL_TYPE_BLUETOOTH,
},
};
-static struct platform_device ventana_bcm4329_rfkill_device = {
- .name = "bcm4329_rfkill",
+static struct platform_device ventana_bt_rfkill_device = {
+ .name = "rfkill_gpio",
.id = -1,
- .num_resources = ARRAY_SIZE(ventana_bcm4329_rfkill_resources),
- .resource = ventana_bcm4329_rfkill_resources,
+ .dev = {
+ .platform_data = ventana_bt_rfkill_pdata,
+ },
};
static void __init ventana_bt_rfkill(void)
{
/*Add Clock Resource*/
- clk_add_alias("bcm4329_32k_clk", ventana_bcm4329_rfkill_device.name, \
+ clk_add_alias("bcm4329_32k_clk", ventana_bt_rfkill_device.name, \
"blink", NULL);
return;
}
@@ -148,8 +121,6 @@ static struct platform_device ventana_bluesleep_device = {
static void __init ventana_setup_bluesleep(void)
{
platform_device_register(&ventana_bluesleep_device);
- tegra_gpio_enable(TEGRA_GPIO_PU6);
- tegra_gpio_enable(TEGRA_GPIO_PU1);
return;
}
@@ -164,19 +135,6 @@ static __initdata struct tegra_clk_init_table ventana_clk_init_table[] = {
{ NULL, NULL, 0, 0},
};
-static struct tegra_ulpi_config ventana_ehci2_ulpi_phy_config = {
- .reset_gpio = TEGRA_GPIO_PV1,
- .clk = "cdev2",
-};
-
-static struct tegra_ehci_platform_data ventana_ehci2_ulpi_platform_data = {
- .operating_mode = TEGRA_USB_HOST,
- .power_down_on_bus_suspend = 1,
- .phy_config = &ventana_ehci2_ulpi_phy_config,
- .phy_type = TEGRA_USB_PHY_TYPE_LINK_ULPI,
- .default_enable = true,
-};
-
static struct tegra_i2c_platform_data ventana_i2c1_platform_data = {
.adapter_nr = 0,
.bus_count = 1,
@@ -368,7 +326,8 @@ static int ventana_wakeup_key(void)
unsigned long status =
readl(IO_ADDRESS(TEGRA_PMC_BASE) + PMC_WAKE_STATUS);
- return status & TEGRA_WAKE_GPIO_PV2 ? KEY_POWER : KEY_RESERVED;
+ return (status & (1 << TEGRA_WAKE_GPIO_PV2)) ?
+ KEY_POWER : KEY_RESERVED;
}
static struct gpio_keys_platform_data ventana_keys_platform_data = {
@@ -384,14 +343,6 @@ static struct platform_device ventana_keys_device = {
.platform_data = &ventana_keys_platform_data,
},
};
-
-static void ventana_keys_init(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(ventana_keys); i++)
- tegra_gpio_enable(ventana_keys[i].gpio);
-}
#endif
static struct platform_device tegra_camera = {
@@ -431,7 +382,7 @@ static struct platform_device *ventana_devices[] __initdata = {
&tegra_das_device,
&spdif_dit_device,
&bluetooth_dit_device,
- &ventana_bcm4329_rfkill_device,
+ &ventana_bt_rfkill_device,
&tegra_pcm_device,
&ventana_audio_device,
};
@@ -498,73 +449,146 @@ static int __init ventana_touch_init_panjit(void)
return 0;
}
-static struct usb_phy_plat_data tegra_usb_phy_pdata[] = {
- [0] = {
- .instance = 0,
- .vbus_irq = TPS6586X_INT_BASE + TPS6586X_INT_USB_DET,
- .vbus_gpio = TEGRA_GPIO_PD0,
+static int __init ventana_gps_init(void)
+{
+ struct clk *clk32 = clk_get_sys(NULL, "blink");
+ if (!IS_ERR(clk32)) {
+ clk_set_rate(clk32,clk32->parent->rate);
+ clk_enable(clk32);
+ }
+
+ tegra_gpio_enable(TEGRA_GPIO_PZ3);
+ return 0;
+}
+
+static struct tegra_usb_platform_data tegra_udc_pdata = {
+ .port_otg = true,
+ .has_hostpc = false,
+ .phy_intf = TEGRA_USB_PHY_INTF_UTMI,
+ .op_mode = TEGRA_USB_OPMODE_DEVICE,
+ .u_data.dev = {
+ .vbus_pmu_irq = 0,
+ .vbus_gpio = -1,
+ .charging_supported = false,
+ .remote_wakeup_supported = false,
},
- [1] = {
- .instance = 1,
- .vbus_gpio = -1,
+ .u_cfg.utmi = {
+ .hssync_start_delay = 0,
+ .elastic_limit = 16,
+ .idle_wait_delay = 17,
+ .term_range_adj = 6,
+ .xcvr_setup = 8,
+ .xcvr_lsfslew = 2,
+ .xcvr_lsrslew = 2,
+ .xcvr_setup_offset = 0,
+ .xcvr_use_fuses = 1,
},
- [2] = {
- .instance = 2,
- .vbus_gpio = TEGRA_GPIO_PD3,
+};
+
+static struct tegra_usb_platform_data tegra_ehci1_utmi_pdata = {
+ .port_otg = true,
+ .has_hostpc = false,
+ .phy_intf = TEGRA_USB_PHY_INTF_UTMI,
+ .op_mode = TEGRA_USB_OPMODE_HOST,
+ .u_data.host = {
+ .vbus_gpio = TEGRA_GPIO_PD0,
+ .vbus_reg = NULL,
+ .hot_plug = true,
+ .remote_wakeup_supported = false,
+ .power_off_on_suspend = true,
+ },
+ .u_cfg.utmi = {
+ .hssync_start_delay = 9,
+ .elastic_limit = 16,
+ .idle_wait_delay = 17,
+ .term_range_adj = 6,
+ .xcvr_setup = 8,
+ .xcvr_lsfslew = 2,
+ .xcvr_lsrslew = 2,
},
};
-static struct tegra_ehci_platform_data tegra_ehci_pdata[] = {
- [0] = {
- .phy_config = &utmi_phy_config[0],
- .operating_mode = TEGRA_USB_HOST,
- .power_down_on_bus_suspend = 1,
- .default_enable = true,
+static void ulpi_link_platform_open(void)
+{
+ int reset_gpio = TEGRA_GPIO_PV1;
+
+ gpio_request(reset_gpio, "ulpi_phy_reset");
+ gpio_direction_output(reset_gpio, 0);
+ tegra_gpio_enable(reset_gpio);
+
+ gpio_direction_output(reset_gpio, 0);
+ msleep(5);
+ gpio_direction_output(reset_gpio, 1);
+}
+
+static struct tegra_usb_phy_platform_ops ulpi_link_plat_ops = {
+ .open = ulpi_link_platform_open,
+};
+
+static struct tegra_usb_platform_data tegra_ehci2_ulpi_link_pdata = {
+ .port_otg = false,
+ .has_hostpc = false,
+ .phy_intf = TEGRA_USB_PHY_INTF_ULPI_LINK,
+ .op_mode = TEGRA_USB_OPMODE_HOST,
+ .u_data.host = {
+ .vbus_gpio = -1,
+ .vbus_reg = NULL,
+ .hot_plug = false,
+ .remote_wakeup_supported = false,
+ .power_off_on_suspend = true,
},
- [1] = {
- .phy_config = &ulpi_phy_config,
- .operating_mode = TEGRA_USB_HOST,
- .power_down_on_bus_suspend = 1,
- .phy_type = TEGRA_USB_PHY_TYPE_LINK_ULPI,
- .default_enable = true,
+ .u_cfg.ulpi = {
+ .shadow_clk_delay = 10,
+ .clock_out_delay = 1,
+ .data_trimmer = 4,
+ .stpdirnxt_trimmer = 4,
+ .dir_trimmer = 4,
+ .clk = "cdev2",
},
- [2] = {
- .phy_config = &utmi_phy_config[1],
- .operating_mode = TEGRA_USB_HOST,
- .power_down_on_bus_suspend = 1,
- .hotplug = 1,
- .default_enable = true,
+ .ops = &ulpi_link_plat_ops,
+};
+
+static struct tegra_usb_platform_data tegra_ehci3_utmi_pdata = {
+ .port_otg = false,
+ .has_hostpc = false,
+ .phy_intf = TEGRA_USB_PHY_INTF_UTMI,
+ .op_mode = TEGRA_USB_OPMODE_HOST,
+ .u_data.host = {
+ .vbus_gpio = TEGRA_GPIO_PD3,
+ .vbus_reg = NULL,
+ .hot_plug = true,
+ .remote_wakeup_supported = false,
+ .power_off_on_suspend = true,
+ },
+ .u_cfg.utmi = {
+ .hssync_start_delay = 9,
+ .elastic_limit = 16,
+ .idle_wait_delay = 17,
+ .term_range_adj = 6,
+ .xcvr_setup = 8,
+ .xcvr_lsfslew = 2,
+ .xcvr_lsrslew = 2,
},
};
-static struct tegra_otg_platform_data tegra_otg_pdata = {
+static struct tegra_usb_otg_data tegra_otg_pdata = {
.ehci_device = &tegra_ehci1_device,
- .ehci_pdata = &tegra_ehci_pdata[0],
+ .ehci_pdata = &tegra_ehci1_utmi_pdata,
};
-static int __init ventana_gps_init(void)
-{
- struct clk *clk32 = clk_get_sys(NULL, "blink");
- if (!IS_ERR(clk32)) {
- clk_set_rate(clk32,clk32->parent->rate);
- clk_enable(clk32);
- }
-
- tegra_gpio_enable(TEGRA_GPIO_PZ3);
- return 0;
-}
-
static void ventana_usb_init(void)
{
- tegra_usb_phy_init(tegra_usb_phy_pdata, ARRAY_SIZE(tegra_usb_phy_pdata));
/* OTG should be the first to be registered */
tegra_otg_device.dev.platform_data = &tegra_otg_pdata;
platform_device_register(&tegra_otg_device);
+ tegra_udc_device.dev.platform_data = &tegra_udc_pdata;
platform_device_register(&tegra_udc_device);
+
+ tegra_ehci2_device.dev.platform_data = &tegra_ehci2_ulpi_link_pdata;
platform_device_register(&tegra_ehci2_device);
- tegra_ehci3_device.dev.platform_data=&tegra_ehci_pdata[2];
+ tegra_ehci3_device.dev.platform_data = &tegra_ehci3_utmi_pdata;
platform_device_register(&tegra_ehci3_device);
}
@@ -576,8 +600,6 @@ static void __init tegra_ventana_init(void)
ventana_pinmux_init();
ventana_i2c_init();
ventana_uart_init();
- tegra_ehci2_device.dev.platform_data
- = &ventana_ehci2_ulpi_platform_data;
platform_add_devices(ventana_devices, ARRAY_SIZE(ventana_devices));
tegra_ram_console_debug_init();
ventana_sdhci_init();
@@ -596,10 +618,6 @@ static void __init tegra_ventana_init(void)
ventana_touch_init_panjit();
}
-#ifdef CONFIG_KEYBOARD_GPIO
- ventana_keys_init();
-#endif
-
ventana_usb_init();
ventana_gps_init();
ventana_panel_init();
diff --git a/arch/arm/mach-tegra/board-whistler-baseband.c b/arch/arm/mach-tegra/board-whistler-baseband.c
index 143d14a8721d..4a479cfb871c 100644
--- a/arch/arm/mach-tegra/board-whistler-baseband.c
+++ b/arch/arm/mach-tegra/board-whistler-baseband.c
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/board-whistler-baseband.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
@@ -16,32 +16,15 @@
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/tegra_caif.h>
#include <mach/tegra_usb_modem_power.h>
-
#include "board.h"
#include "board-whistler-baseband.h"
-static int baseband_phy_on(void);
-static int baseband_phy_off(void);
-static void baseband_phy_restore_start(void);
-static void baseband_phy_restore_end(void);
-
-static struct wake_lock mdm_wake_lock;
-
static struct gpio modem_gpios[] = {
{MODEM_PWR_ON, GPIOF_OUT_INIT_LOW, "MODEM PWR ON"},
{MODEM_RESET, GPIOF_IN, "MODEM RESET"},
- {BB_RST_OUT, GPIOF_IN, "BB RST OUT"},
- {MDM2AP_ACK, GPIOF_IN, "MDM2AP_ACK"},
{AP2MDM_ACK2, GPIOF_OUT_INIT_HIGH, "AP2MDM ACK2"},
{AP2MDM_ACK, GPIOF_OUT_INIT_LOW, "AP2MDM ACK"},
- {ULPI_STP, GPIOF_IN, "ULPI_STP"},
- {ULPI_DIR, GPIOF_OUT_INIT_LOW, "ULPI_DIR"},
- {ULPI_D0, GPIOF_OUT_INIT_LOW, "ULPI_D0"},
- {ULPI_D1, GPIOF_OUT_INIT_LOW, "ULPI_D1"},
};
static __initdata struct tegra_pingroup_config whistler_null_ulpi_pinmux[] = {
@@ -57,78 +40,50 @@ static __initdata struct tegra_pingroup_config whistler_null_ulpi_pinmux[] = {
TEGRA_TRI_NORMAL},
};
-static struct tegra_ulpi_trimmer e1219_trimmer = { 10, 1, 1, 1 };
-
-static struct tegra_ulpi_config ehci2_null_ulpi_phy_config = {
- .trimmer = &e1219_trimmer,
- .post_phy_on = baseband_phy_on,
- .pre_phy_off = baseband_phy_off,
- .phy_restore_start = baseband_phy_restore_start,
- .phy_restore_end = baseband_phy_restore_end,
- .phy_restore_gpio = MDM2AP_ACK,
- .ulpi_dir_gpio = ULPI_DIR,
- .ulpi_d0_gpio = ULPI_D0,
- .ulpi_d1_gpio = ULPI_D1,
-};
+static void baseband_post_phy_on(void);
+static void baseband_pre_phy_off(void);
-static struct tegra_ehci_platform_data ehci2_null_ulpi_platform_data = {
- .operating_mode = TEGRA_USB_HOST,
- .power_down_on_bus_suspend = 0,
- .phy_config = &ehci2_null_ulpi_phy_config,
- .phy_type = TEGRA_USB_PHY_TYPE_NULL_ULPI,
+static struct tegra_usb_phy_platform_ops ulpi_null_plat_ops = {
+ .pre_phy_off = baseband_pre_phy_off,
+ .post_phy_on = baseband_post_phy_on,
};
-static int __init tegra_null_ulpi_init(void)
-{
- tegra_ehci2_device.dev.platform_data = &ehci2_null_ulpi_platform_data;
- platform_device_register(&tegra_ehci2_device);
- return 0;
-}
-
-static irqreturn_t mdm_start_thread(int irq, void *data)
-{
- if (gpio_get_value(BB_RST_OUT)) {
- pr_info("BB_RST_OUT high\n");
- } else {
- pr_info("BB_RST_OUT low\n");
- /* hold wait lock to complete the enumeration */
- wake_lock_timeout(&mdm_wake_lock, HZ * 10);
- }
-
- return IRQ_HANDLED;
-}
-
-static int baseband_phy_on(void)
-{
- static bool phy_init;
-
- if (!phy_init) {
- /* set AP2MDM_ACK2 low */
- gpio_set_value(AP2MDM_ACK2, 0);
- phy_init = true;
- }
- pr_info("%s\n", __func__);
- return 0;
-}
+static struct tegra_usb_platform_data tegra_ehci2_ulpi_null_pdata = {
+ .port_otg = false,
+ .has_hostpc = false,
+ .phy_intf = TEGRA_USB_PHY_INTF_ULPI_NULL,
+ .op_mode = TEGRA_USB_OPMODE_HOST,
+ .u_data.host = {
+ .vbus_gpio = -1,
+ .vbus_reg = NULL,
+ .hot_plug = false,
+ .remote_wakeup_supported = false,
+ .power_off_on_suspend = true,
+ },
+ .u_cfg.ulpi = {
+ .shadow_clk_delay = 10,
+ .clock_out_delay = 1,
+ .data_trimmer = 1,
+ .stpdirnxt_trimmer = 1,
+ .dir_trimmer = 1,
+ .clk = NULL,
+ .phy_restore_gpio = MDM2AP_ACK,
+ },
+ .ops = &ulpi_null_plat_ops,
+};
-static int baseband_phy_off(void)
+static void baseband_post_phy_on(void)
{
- pr_info("%s\n", __func__);
- return 0;
+ /* set AP2MDM_ACK2 low */
+ gpio_set_value(AP2MDM_ACK2, 0);
}
-static void baseband_phy_restore_start(void)
+static void baseband_pre_phy_off(void)
{
/* set AP2MDM_ACK2 high */
gpio_set_value(AP2MDM_ACK2, 1);
}
-static void baseband_phy_restore_end(void)
-{
- /* set AP2MDM_ACK2 low */
- gpio_set_value(AP2MDM_ACK2, 0);
-}
-
static void baseband_start(void)
{
/*
@@ -150,7 +105,6 @@ static void baseband_reset(void)
static int baseband_init(void)
{
- int irq;
int ret;
ret = gpio_request_array(modem_gpios, ARRAY_SIZE(modem_gpios));
@@ -161,43 +115,9 @@ static int baseband_init(void)
tegra_pinmux_set_pullupdown(TEGRA_PINGROUP_UAC,
TEGRA_PUPD_PULL_UP);
- tegra_gpio_enable(MODEM_PWR_ON);
- tegra_gpio_enable(MODEM_RESET);
- tegra_gpio_enable(AP2MDM_ACK2);
- tegra_gpio_enable(BB_RST_OUT);
- tegra_gpio_enable(AP2MDM_ACK);
- tegra_gpio_enable(MDM2AP_ACK);
- tegra_gpio_enable(TEGRA_GPIO_PY3);
- tegra_gpio_enable(TEGRA_GPIO_PY1);
- tegra_gpio_enable(TEGRA_GPIO_PO1);
- tegra_gpio_enable(TEGRA_GPIO_PO2);
-
/* export GPIO for user space access through sysfs */
gpio_export(MODEM_PWR_ON, false);
- /* phy init */
- tegra_null_ulpi_init();
-
- wake_lock_init(&mdm_wake_lock, WAKE_LOCK_SUSPEND, "mdm_lock");
-
- /* enable IRQ for BB_RST_OUT */
- irq = gpio_to_irq(BB_RST_OUT);
-
- ret = request_threaded_irq(irq, NULL, mdm_start_thread,
- IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
- "mdm_start", NULL);
- if (ret < 0) {
- pr_err("%s: request_threaded_irq error\n", __func__);
- return ret;
- }
-
- ret = enable_irq_wake(irq);
- if (ret) {
- pr_err("%s: enable_irq_wake error\n", __func__);
- free_irq(irq, NULL);
- return ret;
- }
-
return 0;
}
@@ -210,7 +130,13 @@ static const struct tegra_modem_operations baseband_operations = {
static struct tegra_usb_modem_power_platform_data baseband_pdata = {
.ops = &baseband_operations,
.wake_gpio = MDM2AP_ACK2,
- .flags = IRQF_TRIGGER_FALLING,
+ .wake_irq_flags = IRQF_TRIGGER_FALLING,
+ .boot_gpio = BB_RST_OUT,
+ .boot_irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ .autosuspend_delay = 2000,
+ .short_autosuspend_delay = 50,
+ .tegra_ehci_device = &tegra_ehci2_device,
+ .tegra_ehci_pdata = &tegra_ehci2_ulpi_null_pdata,
};
static struct platform_device icera_baseband_device = {
diff --git a/arch/arm/mach-tegra/board-whistler-panel.c b/arch/arm/mach-tegra/board-whistler-panel.c
index 74075d4659c5..d727675c1421 100644
--- a/arch/arm/mach-tegra/board-whistler-panel.c
+++ b/arch/arm/mach-tegra/board-whistler-panel.c
@@ -29,7 +29,7 @@
#include <linux/pwm_backlight.h>
#include <linux/tegra_pwm_bl.h>
#include <linux/nvhost.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include <mach/irqs.h>
#include <mach/iomap.h>
#include <mach/dc.h>
@@ -38,6 +38,7 @@
#include "devices.h"
#include "gpio-names.h"
#include "board.h"
+#include "tegra2_host1x_devices.h"
#define whistler_hdmi_hpd TEGRA_GPIO_PN7
@@ -58,7 +59,6 @@ static struct platform_tegra_pwm_backlight_data whistler_disp1_backlight_data =
.max_brightness = 256,
.dft_brightness = 77,
.gpio_conf_to_sfio = TEGRA_GPIO_PW1,
- .switch_to_sfio = &tegra_gpio_disable,
.period = 0x1F,
.clk_div = 3,
.clk_select = 2,
@@ -318,25 +318,19 @@ static void whistler_panel_early_suspend(struct early_suspend *h)
fb_blank(registered_fb[1], FB_BLANK_NORMAL);
#ifdef CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND
- cpufreq_save_default_governor();
- cpufreq_set_conservative_governor();
- cpufreq_set_conservative_governor_param("up_threshold",
- SET_CONSERVATIVE_GOVERNOR_UP_THRESHOLD);
-
- cpufreq_set_conservative_governor_param("down_threshold",
- SET_CONSERVATIVE_GOVERNOR_DOWN_THRESHOLD);
-
- cpufreq_set_conservative_governor_param("freq_step",
- SET_CONSERVATIVE_GOVERNOR_FREQ_STEP);
+ cpufreq_store_default_gov();
+ cpufreq_change_gov(cpufreq_conservative_gov);
#endif
}
static void whistler_panel_late_resume(struct early_suspend *h)
{
unsigned i;
+
#ifdef CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND
- cpufreq_restore_default_governor();
+ cpufreq_restore_default_gov();
#endif
+
for (i = 0; i < num_registered_fb; i++)
fb_blank(registered_fb[i], FB_BLANK_UNBLANK);
}
@@ -347,7 +341,6 @@ int __init whistler_panel_init(void)
int err;
struct resource __maybe_unused *res;
- tegra_gpio_enable(whistler_hdmi_hpd);
gpio_request(whistler_hdmi_hpd, "hdmi_hpd");
gpio_direction_input(whistler_hdmi_hpd);
@@ -364,7 +357,7 @@ int __init whistler_panel_init(void)
#endif
#ifdef CONFIG_TEGRA_GRHOST
- err = nvhost_device_register(&tegra_grhost_device);
+ err = tegra2_register_host1x_devices();
if (err)
return err;
#endif
diff --git a/arch/arm/mach-tegra/board-whistler-pinmux.c b/arch/arm/mach-tegra/board-whistler-pinmux.c
index 22c2f984c662..15ae9c76b19d 100644
--- a/arch/arm/mach-tegra/board-whistler-pinmux.c
+++ b/arch/arm/mach-tegra/board-whistler-pinmux.c
@@ -64,13 +64,15 @@
}
static __initdata struct tegra_drive_pingroup_config whistler_drive_pinmux[] = {
- DEFAULT_DRIVE(DBG),
- DEFAULT_DRIVE(DDC),
DEFAULT_DRIVE(VI1),
- DEFAULT_DRIVE(VI2),
DEFAULT_DRIVE(SDIO1),
SET_DRIVE(DAP2, DISABLE, ENABLE, DIV_1, 46, 46, SLOWEST, SLOWEST),
SET_DRIVE(DAP3, DISABLE, ENABLE, DIV_1, 46, 46, SLOWEST, SLOWEST),
+ SET_DRIVE(DBG, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST), /* I2C1 */
+ SET_DRIVE(DDC, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST), /* I2C2-1 */
+ SET_DRIVE(AT1, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST), /* I2C2-2 */
+ SET_DRIVE(VI2, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST), /* I2C3 */
+ SET_DRIVE(AO1, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST), /* DVC */
};
static __initdata struct tegra_pingroup_config whistler_pinmux[] = {
@@ -93,7 +95,7 @@ static __initdata struct tegra_pingroup_config whistler_pinmux[] = {
{TEGRA_PINGROUP_DTC, TEGRA_MUX_VI, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_DTD, TEGRA_MUX_VI, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_DTE, TEGRA_MUX_RSVD1, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_DTF, TEGRA_MUX_I2C3, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_DTF, TEGRA_MUX_I2C3, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_GMA, TEGRA_MUX_GMI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_GMB, TEGRA_MUX_GMI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_GMC, TEGRA_MUX_GMI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
@@ -103,7 +105,7 @@ static __initdata struct tegra_pingroup_config whistler_pinmux[] = {
{TEGRA_PINGROUP_GPU7, TEGRA_MUX_RTCK, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_GPV, TEGRA_MUX_PCIE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_HDINT, TEGRA_MUX_HDMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_I2CP, TEGRA_MUX_I2C, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_I2CP, TEGRA_MUX_I2C, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_IRRX, TEGRA_MUX_UARTB, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_IRTX, TEGRA_MUX_UARTB, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_KBCA, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
@@ -155,7 +157,7 @@ static __initdata struct tegra_pingroup_config whistler_pinmux[] = {
{TEGRA_PINGROUP_OWC, TEGRA_MUX_OWR, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
{TEGRA_PINGROUP_PMC, TEGRA_MUX_PWR_ON, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_PTA, TEGRA_MUX_HDMI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_RM, TEGRA_MUX_I2C, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_RM, TEGRA_MUX_I2C, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_SDB, TEGRA_MUX_SDIO3, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_SDC, TEGRA_MUX_SDIO3, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_SDD, TEGRA_MUX_SDIO3, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
diff --git a/arch/arm/mach-tegra/board-whistler-power.c b/arch/arm/mach-tegra/board-whistler-power.c
index a0eb6686b0db..67663252e0d9 100644
--- a/arch/arm/mach-tegra/board-whistler-power.c
+++ b/arch/arm/mach-tegra/board-whistler-power.c
@@ -31,7 +31,6 @@
#include "gpio-names.h"
#include "fuse.h"
#include "pm.h"
-#include "wakeups-t2.h"
#include "board.h"
#define PMC_CTRL 0x0
diff --git a/arch/arm/mach-tegra/board-whistler-sdhci.c b/arch/arm/mach-tegra/board-whistler-sdhci.c
index d98b1d53a52e..5721a2e179df 100644
--- a/arch/arm/mach-tegra/board-whistler-sdhci.c
+++ b/arch/arm/mach-tegra/board-whistler-sdhci.c
@@ -2,7 +2,7 @@
* arch/arm/mach-tegra/board-whistler-sdhci.c
*
* Copyright (C) 2010 Google, Inc.
- * Copyright (C) 2011 NVIDIA Corporation.
+ * Copyright (C) 2011-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
@@ -168,6 +168,7 @@ static struct tegra_sdhci_platform_data tegra_sdhci_platform_data1 = {
.embedded_sdio = &embedded_sdio_data1,
#endif
.built_in = 0,
+ .ocr_mask = MMC_OCR_1V8_MASK,
},
#ifndef CONFIG_MMC_EMBEDDED_SDIO
.pm_flags = MMC_PM_KEEP_POWER,
@@ -243,10 +244,6 @@ static int __init whistler_wifi_init(void)
gpio_request(WHISTLER_WLAN_RST, "wlan_rst");
gpio_request(WHISTLER_WLAN_WOW, "bcmsdh_sdmmc");
- tegra_gpio_enable(WHISTLER_WLAN_PWR);
- tegra_gpio_enable(WHISTLER_WLAN_RST);
- tegra_gpio_enable(WHISTLER_WLAN_WOW);
-
gpio_direction_output(WHISTLER_WLAN_PWR, 0);
gpio_direction_output(WHISTLER_WLAN_RST, 0);
gpio_direction_input(WHISTLER_WLAN_WOW);
@@ -256,10 +253,6 @@ static int __init whistler_wifi_init(void)
}
int __init whistler_sdhci_init(void)
{
- int ret;
-
- tegra_gpio_enable(WHISTLER_EXT_SDCARD_DETECT);
-
platform_device_register(&tegra_sdhci_device3);
platform_device_register(&tegra_sdhci_device2);
platform_device_register(&tegra_sdhci_device1);
diff --git a/arch/arm/mach-tegra/board-whistler-sensors.c b/arch/arm/mach-tegra/board-whistler-sensors.c
index 95bb2f1dd405..9783347cd631 100644
--- a/arch/arm/mach-tegra/board-whistler-sensors.c
+++ b/arch/arm/mach-tegra/board-whistler-sensors.c
@@ -70,37 +70,30 @@ static struct regulator *reg_vddio_vi; /* LDO18 */
static int whistler_camera_init(void)
{
- tegra_gpio_enable(CAMERA1_PWDN_GPIO);
gpio_request(CAMERA1_PWDN_GPIO, "camera1_powerdown");
gpio_direction_output(CAMERA1_PWDN_GPIO, 0);
gpio_export(CAMERA1_PWDN_GPIO, false);
- tegra_gpio_enable(CAMERA1_RESET_GPIO);
gpio_request(CAMERA1_RESET_GPIO, "camera1_reset");
gpio_direction_output(CAMERA1_RESET_GPIO, 0);
gpio_export(CAMERA1_RESET_GPIO, false);
- tegra_gpio_enable(CAMERA2_PWDN_GPIO);
gpio_request(CAMERA2_PWDN_GPIO, "camera2_powerdown");
gpio_direction_output(CAMERA2_PWDN_GPIO, 0);
gpio_export(CAMERA2_PWDN_GPIO, false);
- tegra_gpio_enable(CAMERA2_RESET_GPIO);
gpio_request(CAMERA2_RESET_GPIO, "camera2_reset");
gpio_direction_output(CAMERA2_RESET_GPIO, 0);
gpio_export(CAMERA2_RESET_GPIO, false);
- tegra_gpio_enable(CAMERA_AF_PD_GPIO);
gpio_request(CAMERA_AF_PD_GPIO, "camera_autofocus");
gpio_direction_output(CAMERA_AF_PD_GPIO, 0);
gpio_export(CAMERA_AF_PD_GPIO, false);
- tegra_gpio_enable(CAMERA_FLASH_EN1_GPIO);
gpio_request(CAMERA_FLASH_EN1_GPIO, "camera_flash_en1");
gpio_direction_output(CAMERA_FLASH_EN1_GPIO, 0);
gpio_export(CAMERA_FLASH_EN1_GPIO, false);
- tegra_gpio_enable(CAMERA_FLASH_EN2_GPIO);
gpio_request(CAMERA_FLASH_EN2_GPIO, "camera_flash_en2");
gpio_direction_output(CAMERA_FLASH_EN2_GPIO, 0);
gpio_export(CAMERA_FLASH_EN2_GPIO, false);
@@ -293,14 +286,12 @@ static struct i2c_board_info whistler_i2c3_board_info[] = {
static void whistler_adxl34x_init(void)
{
- tegra_gpio_enable(ADXL34X_IRQ_GPIO);
gpio_request(ADXL34X_IRQ_GPIO, "adxl34x");
gpio_direction_input(ADXL34X_IRQ_GPIO);
}
static void whistler_isl29018_init(void)
{
- tegra_gpio_enable(ISL29018_IRQ_GPIO);
gpio_request(ISL29018_IRQ_GPIO, "isl29018");
gpio_direction_input(ISL29018_IRQ_GPIO);
}
@@ -316,11 +307,6 @@ static struct i2c_board_info whistler_i2c1_board_info[] = {
},
};
-static void whistler_adt7461_init(void)
-{
- tegra_gpio_enable(ADT7461_IRQ_GPIO);
-}
-
static struct adt7461_platform_data whistler_adt7461_pdata = {
.supported_hwrev = true,
.ext_range = false,
@@ -355,8 +341,6 @@ int __init whistler_sensors_init(void)
whistler_isl29018_init();
- whistler_adt7461_init();
-
i2c_register_board_info(0, whistler_i2c1_board_info,
ARRAY_SIZE(whistler_i2c1_board_info));
diff --git a/arch/arm/mach-tegra/board-whistler.c b/arch/arm/mach-tegra/board-whistler.c
index f1246454ed1b..06e704e47870 100644
--- a/arch/arm/mach-tegra/board-whistler.c
+++ b/arch/arm/mach-tegra/board-whistler.c
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/board-whistler.c
*
- * 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
@@ -37,6 +37,7 @@
#include <linux/mfd/max8907c.h>
#include <linux/memblock.h>
#include <linux/tegra_uart.h>
+#include <linux/rfkill-gpio.h>
#include <mach/clk.h>
#include <mach/iomap.h>
@@ -169,21 +170,21 @@ static void __init whistler_uart_init(void)
platform_add_devices(whistler_uart_devices,
ARRAY_SIZE(whistler_uart_devices));
}
-
-static struct resource whistler_bcm4329_rfkill_resources[] = {
+static struct rfkill_gpio_platform_data whistler_bt_rfkill_pdata[] = {
{
- .name = "bcm4329_nshutdown_gpio",
- .start = TEGRA_GPIO_PU0,
- .end = TEGRA_GPIO_PU0,
- .flags = IORESOURCE_IO,
+ .name = "bt_rfkill",
+ .shutdown_gpio = TEGRA_GPIO_PU0,
+ .reset_gpio = TEGRA_GPIO_INVALID,
+ .type = RFKILL_TYPE_BLUETOOTH,
},
};
-static struct platform_device whistler_bcm4329_rfkill_device = {
- .name = "bcm4329_rfkill",
- .id = -1,
- .num_resources = ARRAY_SIZE(whistler_bcm4329_rfkill_resources),
- .resource = whistler_bcm4329_rfkill_resources,
+static struct platform_device whistler_bt_rfkill_device = {
+ .name = "rfkill_gpio",
+ .id = -1,
+ .dev = {
+ .platform_data = whistler_bt_rfkill_pdata,
+ },
};
static struct resource whistler_bluesleep_resources[] = {
@@ -217,37 +218,9 @@ static struct platform_device whistler_bluesleep_device = {
static void __init whistler_setup_bluesleep(void)
{
platform_device_register(&whistler_bluesleep_device);
- tegra_gpio_enable(TEGRA_GPIO_PU6);
- tegra_gpio_enable(TEGRA_GPIO_PU1);
return;
}
-static struct tegra_utmip_config utmi_phy_config[] = {
- [0] = {
- .hssync_start_delay = 9,
- .idle_wait_delay = 17,
- .elastic_limit = 16,
- .term_range_adj = 6,
- .xcvr_setup = 15,
- .xcvr_lsfslew = 2,
- .xcvr_lsrslew = 2,
- },
- [1] = {
- .hssync_start_delay = 9,
- .idle_wait_delay = 17,
- .elastic_limit = 16,
- .term_range_adj = 6,
- .xcvr_setup = 8,
- .xcvr_lsfslew = 2,
- .xcvr_lsrslew = 2,
- },
-};
-
-static struct tegra_ulpi_config ulpi_phy_config = {
- .reset_gpio = TEGRA_GPIO_PG2,
- .clk = "cdev2",
-};
-
static __initdata struct tegra_clk_init_table whistler_clk_init_table[] = {
/* name parent rate enabled */
{ "pwm", "clk_32k", 32768, false},
@@ -266,6 +239,7 @@ static struct tegra_i2c_platform_data whistler_i2c1_platform_data = {
.scl_gpio = {TEGRA_GPIO_PC4, 0},
.sda_gpio = {TEGRA_GPIO_PC5, 0},
.arb_recovery = arb_lost_recovery,
+ .slave_addr = 0xFC,
};
static const struct tegra_pingroup_config i2c2_ddc = {
@@ -287,6 +261,7 @@ static struct tegra_i2c_platform_data whistler_i2c2_platform_data = {
.scl_gpio = {0, TEGRA_GPIO_PT5},
.sda_gpio = {0, TEGRA_GPIO_PT6},
.arb_recovery = arb_lost_recovery,
+ .slave_addr = 0xFC,
};
static struct tegra_i2c_platform_data whistler_i2c3_platform_data = {
@@ -296,6 +271,7 @@ static struct tegra_i2c_platform_data whistler_i2c3_platform_data = {
.scl_gpio = {TEGRA_GPIO_PBB2, 0},
.sda_gpio = {TEGRA_GPIO_PBB3, 0},
.arb_recovery = arb_lost_recovery,
+ .slave_addr = 0xFC,
};
static struct tegra_i2c_platform_data whistler_dvc_platform_data = {
@@ -416,7 +392,7 @@ static struct platform_device *whistler_devices[] __initdata = {
&spdif_dit_device,
&bluetooth_dit_device,
&baseband_dit_device,
- &whistler_bcm4329_rfkill_device,
+ &whistler_bt_rfkill_device,
&tegra_pcm_device,
&whistler_audio_aic326x_device,
&whistler_audio_wm8753_device,
@@ -437,76 +413,70 @@ static const struct i2c_board_info whistler_i2c_touch_info[] = {
static int __init whistler_touch_init(void)
{
- tegra_gpio_enable(TEGRA_GPIO_PC6);
i2c_register_board_info(0, whistler_i2c_touch_info, 1);
return 0;
}
-static int __init whistler_scroll_init(void)
-{
- int i;
- for (i = 0; i < ARRAY_SIZE(scroll_keys); i++)
- tegra_gpio_enable(scroll_keys[i].gpio);
-
- return 0;
-}
-
-static struct usb_phy_plat_data tegra_usb_phy_pdata[] = {
- [0] = {
- .instance = 0,
- .vbus_irq = MAX8907C_INT_BASE + MAX8907C_IRQ_VCHG_DC_R,
- .vbus_gpio = USB1_VBUS_GPIO,
- },
- [1] = {
- .instance = 1,
- .vbus_gpio = -1,
+static struct tegra_usb_platform_data tegra_udc_pdata = {
+ .port_otg = true,
+ .has_hostpc = false,
+ .phy_intf = TEGRA_USB_PHY_INTF_UTMI,
+ .op_mode = TEGRA_USB_OPMODE_DEVICE,
+ .u_data.dev = {
+ .vbus_pmu_irq = MAX8907C_INT_BASE + MAX8907C_IRQ_VCHG_DC_R,
+ .vbus_gpio = -1,
+ .charging_supported = false,
+ .remote_wakeup_supported = false,
},
- [2] = {
- .instance = 2,
- .vbus_gpio = -1,
+ .u_cfg.utmi = {
+ .hssync_start_delay = 0,
+ .elastic_limit = 16,
+ .idle_wait_delay = 17,
+ .term_range_adj = 6,
+ .xcvr_setup = 8,
+ .xcvr_lsfslew = 2,
+ .xcvr_lsrslew = 2,
+ .xcvr_setup_offset = 0,
+ .xcvr_use_fuses = 1,
},
};
-static struct tegra_ehci_platform_data tegra_ehci_pdata[] = {
- [0] = {
- .phy_config = &utmi_phy_config[0],
- .operating_mode = TEGRA_USB_HOST,
- .power_down_on_bus_suspend = 1,
- .default_enable = false,
- },
- [1] = {
- .phy_config = &ulpi_phy_config,
- .operating_mode = TEGRA_USB_HOST,
- .power_down_on_bus_suspend = 1,
- .default_enable = false,
- },
- [2] = {
- .phy_config = &utmi_phy_config[1],
- .operating_mode = TEGRA_USB_HOST,
- .power_down_on_bus_suspend = 1,
- .default_enable = false,
+static struct tegra_usb_platform_data tegra_ehci1_utmi_pdata = {
+ .port_otg = true,
+ .has_hostpc = false,
+ .phy_intf = TEGRA_USB_PHY_INTF_UTMI,
+ .op_mode = TEGRA_USB_OPMODE_HOST,
+ .u_data.host = {
+ .vbus_gpio = TEGRA_GPIO_PN6,
+ .vbus_reg = NULL,
+ .hot_plug = true,
+ .remote_wakeup_supported = false,
+ .power_off_on_suspend = true,
+ },
+ .u_cfg.utmi = {
+ .hssync_start_delay = 9,
+ .elastic_limit = 16,
+ .idle_wait_delay = 17,
+ .term_range_adj = 6,
+ .xcvr_setup = 8,
+ .xcvr_lsfslew = 2,
+ .xcvr_lsrslew = 2,
},
};
-static struct tegra_otg_platform_data tegra_otg_pdata = {
+static struct tegra_usb_otg_data tegra_otg_pdata = {
.ehci_device = &tegra_ehci1_device,
- .ehci_pdata = &tegra_ehci_pdata[0],
+ .ehci_pdata = &tegra_ehci1_utmi_pdata,
};
-static int __init whistler_gps_init(void)
-{
- tegra_gpio_enable(TEGRA_GPIO_PU4);
- return 0;
-}
-
+#define SERIAL_NUMBER_LENGTH 20
static void whistler_usb_init(void)
{
- tegra_usb_phy_init(tegra_usb_phy_pdata, ARRAY_SIZE(tegra_usb_phy_pdata));
-
tegra_otg_device.dev.platform_data = &tegra_otg_pdata;
platform_device_register(&tegra_otg_device);
+ tegra_udc_device.dev.platform_data = &tegra_udc_pdata;
}
static void __init tegra_whistler_init(void)
@@ -524,9 +494,7 @@ static void __init tegra_whistler_init(void)
whistler_sensors_init();
whistler_touch_init();
whistler_kbc_init();
- whistler_gps_init();
whistler_usb_init();
- whistler_scroll_init();
whistler_emc_init();
if (modem_id == 0x1)
whistler_baseband_init();
diff --git a/arch/arm/mach-tegra/board.h b/arch/arm/mach-tegra/board.h
index c7ab065bc195..7c081fad642a 100644
--- a/arch/arm/mach-tegra/board.h
+++ b/arch/arm/mach-tegra/board.h
@@ -157,16 +157,17 @@ void tegra_get_board_info(struct board_info *);
void tegra_get_pmu_board_info(struct board_info *bi);
void tegra_get_display_board_info(struct board_info *bi);
void tegra_get_camera_board_info(struct board_info *bi);
+
#ifdef CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND
-#define SET_CONSERVATIVE_GOVERNOR_UP_THRESHOLD 95
-#define SET_CONSERVATIVE_GOVERNOR_DOWN_THRESHOLD 50
-#define SET_CONSERVATIVE_GOVERNOR_FREQ_STEP 3
-
-void cpufreq_save_default_governor(void);
-void cpufreq_restore_default_governor(void);
-void cpufreq_set_conservative_governor(void);
-void cpufreq_set_conservative_governor_param(char *name, int value);
+#define MAX_GOV_NAME_LEN 16
+extern char cpufreq_default_gov[][MAX_GOV_NAME_LEN];
+extern char *cpufreq_conservative_gov;
+
+void cpufreq_store_default_gov(void);
+void cpufreq_restore_default_gov(void);
+void cpufreq_change_gov(char *target_gov);
#endif
+
int get_core_edp(void);
enum panel_type get_panel_type(void);
int tegra_get_modem_id(void);
diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c
index f31da0bf1494..66a954fb6696 100644
--- a/arch/arm/mach-tegra/clock.c
+++ b/arch/arm/mach-tegra/clock.c
@@ -238,16 +238,9 @@ void clk_init(struct clk *c)
static int clk_enable_locked(struct clk *c)
{
int ret = 0;
- int rate = clk_get_rate_locked(c);
- bool set_rate = false;
-
- if (rate > c->max_rate) {
- rate = c->max_rate;
- set_rate = true;
- }
if (clk_is_auto_dvfs(c)) {
- ret = tegra_dvfs_set_rate(c, rate);
+ ret = tegra_dvfs_set_rate(c, clk_get_rate_locked(c));
if (ret)
return ret;
}
@@ -259,9 +252,6 @@ static int clk_enable_locked(struct clk *c)
return ret;
}
- if (set_rate)
- clk_set_rate_locked(c, rate);
-
if (c->ops && c->ops->enable) {
ret = c->ops->enable(c);
trace_clock_enable(c->name, 1, 0);
@@ -525,13 +515,11 @@ unsigned long clk_get_rate_all_locked(struct clk *c)
return rate;
}
-long clk_round_rate(struct clk *c, unsigned long rate)
+long clk_round_rate_locked(struct clk *c, unsigned long rate)
{
- unsigned long flags, max_rate;
+ unsigned long max_rate;
long ret;
- clk_lock_save(c, &flags);
-
if (!c->ops || !c->ops->round_rate) {
ret = -ENOSYS;
goto out;
@@ -544,6 +532,16 @@ long clk_round_rate(struct clk *c, unsigned long rate)
ret = c->ops->round_rate(c, rate);
out:
+ return ret;
+}
+
+long clk_round_rate(struct clk *c, unsigned long rate)
+{
+ unsigned long flags;
+ long ret;
+
+ clk_lock_save(c, &flags);
+ ret = clk_round_rate_locked(c, rate);
clk_unlock_restore(c, &flags);
return ret;
}
@@ -1299,6 +1297,10 @@ static int clk_debugfs_register_one(struct clk *c)
if (!d)
goto err_out;
+ d = debugfs_create_u32("min", S_IRUGO, c->dent, (u32 *)&c->min_rate);
+ if (!d)
+ goto err_out;
+
d = debugfs_create_file(
"parent", parent_rate_mode, c->dent, c, &parent_fops);
if (!d)
diff --git a/arch/arm/mach-tegra/clock.h b/arch/arm/mach-tegra/clock.h
index dde9e07292a7..c27176b1cc0d 100644
--- a/arch/arm/mach-tegra/clock.h
+++ b/arch/arm/mach-tegra/clock.h
@@ -76,6 +76,12 @@ struct clk_mux_sel {
u32 value;
};
+struct clk_backup {
+ struct clk *input;
+ u32 value;
+ unsigned long bus_rate;
+};
+
struct clk_pll_freq_table {
unsigned long input_rate;
unsigned long output_rate;
@@ -152,7 +158,7 @@ struct clk {
u32 reg_shift;
struct list_head shared_bus_list;
- struct clk_mux_sel shared_bus_backup;
+ struct clk_backup shared_bus_backup;
union {
struct {
@@ -240,6 +246,7 @@ unsigned long clk_get_min_rate(struct clk *c);
unsigned long clk_get_rate_locked(struct clk *c);
int clk_set_rate_locked(struct clk *c, unsigned long rate);
int clk_set_parent_locked(struct clk *c, struct clk *parent);
+long clk_round_rate_locked(struct clk *c, unsigned long rate);
int tegra_clk_shared_bus_update(struct clk *c);
void tegra2_sdmmc_tap_delay(struct clk *c, int delay);
void tegra3_set_cpu_skipper_delay(int delay);
@@ -248,9 +255,12 @@ long tegra_emc_round_rate(unsigned long rate);
struct clk *tegra_emc_predict_parent(unsigned long rate, u32 *div_value);
void tegra_emc_timing_invalidate(void);
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+static inline int tegra_emc_backup(unsigned long rate)
+{ return 0; }
static inline bool tegra_clk_is_parent_allowed(struct clk *c, struct clk *p)
{ return true; }
#else
+int tegra_emc_backup(unsigned long rate);
bool tegra_clk_is_parent_allowed(struct clk *c, struct clk *p);
#endif
diff --git a/arch/arm/mach-tegra/common-t2.c b/arch/arm/mach-tegra/common-t2.c
index 6f9b177892ce..f90dfce6a690 100644
--- a/arch/arm/mach-tegra/common-t2.c
+++ b/arch/arm/mach-tegra/common-t2.c
@@ -3,7 +3,7 @@
*
* Tegra 2 SoC-specific initialization (memory controller, etc.)
*
- * Copyright (c) 2009-2011, NVIDIA Corporation.
+ * Copyright (c) 2009-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
@@ -177,16 +177,18 @@ out:
return IRQ_HANDLED;
}
-void __init tegra_mc_init(void)
+static int __init tegra_mc_init(void)
{
if (request_irq(INT_MC_GENERAL, tegra_mc_error_isr, 0,
"mc_status", NULL)) {
pr_err("%s: unable to register MC error interrupt\n", __func__);
+ return -EINVAL;
} else {
void __iomem *mc = IO_ADDRESS(TEGRA_MC_BASE);
u32 reg = MC_INT_SECURITY_VIOLATION | MC_INT_INVALID_GART_PAGE |
MC_INT_DECERR_EMEM_OTHERS;
writel(reg, mc + MC_INT_MASK);
}
+ return 0;
}
arch_initcall(tegra_mc_init);
diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c
index 2117b3de64e0..e4e22f813171 100644
--- a/arch/arm/mach-tegra/common.c
+++ b/arch/arm/mach-tegra/common.c
@@ -28,6 +28,7 @@
#include <linux/memblock.h>
#include <linux/bitops.h>
#include <linux/sched.h>
+#include <linux/cpufreq.h>
#include <asm/hardware/cache-l2x0.h>
#include <asm/system.h>
@@ -345,6 +346,7 @@ void tegra_init_cache(bool init)
writel(0x770, p + L2X0_DATA_LATENCY_CTRL);
#endif
#endif
+ writel(0x3, p + L2X0_POWER_CTRL);
aux_ctrl = readl(p + L2X0_CACHE_TYPE);
aux_ctrl = (aux_ctrl & 0x700) << (17-8);
aux_ctrl |= 0x7C000001;
@@ -998,118 +1000,77 @@ void __init tegra_release_bootloader_fb(void)
}
#ifdef CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND
-static char cpufreq_gov_default[32];
-static char *cpufreq_gov_conservative = "conservative";
-static char *cpufreq_sysfs_place_holder="/sys/devices/system/cpu/cpu%i/cpufreq/scaling_governor";
-static char *cpufreq_gov_conservative_param="/sys/devices/system/cpu/cpufreq/conservative/%s";
+char cpufreq_default_gov[CONFIG_NR_CPUS][MAX_GOV_NAME_LEN];
+char *cpufreq_conservative_gov = "conservative";
-static void cpufreq_set_governor(char *governor)
+void cpufreq_store_default_gov(void)
{
- struct file *scaling_gov = NULL;
- mm_segment_t old_fs;
- char buf[128];
- int i = 0;
- loff_t offset = 0;
+ unsigned int cpu = 0;
+ struct cpufreq_policy *policy;
- if (governor == NULL)
- return;
-
- /* change to KERNEL_DS address limit */
- old_fs = get_fs();
- set_fs(KERNEL_DS);
#ifndef CONFIG_TEGRA_AUTO_HOTPLUG
- for_each_online_cpu(i)
+ for_each_online_cpu(cpu)
#endif
{
- sprintf(buf, cpufreq_sysfs_place_holder, i);
- scaling_gov = filp_open(buf, O_RDWR, 0);
- if (scaling_gov != NULL) {
- if (scaling_gov->f_op != NULL &&
- scaling_gov->f_op->write != NULL)
- scaling_gov->f_op->write(scaling_gov,
- governor,
- strlen(governor),
- &offset);
- else
- pr_err("f_op might be null\n");
-
- filp_close(scaling_gov, NULL);
+ policy = cpufreq_cpu_get(cpu);
+ if (policy && policy->governor) {
+ sprintf(cpufreq_default_gov[cpu], "%s",
+ policy->governor->name);
+ cpufreq_cpu_put(policy);
} else {
- pr_err("%s. Can't open %s\n", __func__, buf);
+ /* No policy or no gov set for this
+ * online cpu. If we are here, require
+ * serious debugging hence setting
+ * as pr_error.
+ */
+ pr_err("No gov or No policy for online cpu:%d,"
+ , cpu);
}
}
- set_fs(old_fs);
}
-void cpufreq_save_default_governor(void)
+void cpufreq_change_gov(char *target_gov)
{
- struct file *scaling_gov = NULL;
- mm_segment_t old_fs;
- char buf[128];
- loff_t offset = 0;
-
- /* change to KERNEL_DS address limit */
- old_fs = get_fs();
- set_fs(KERNEL_DS);
-
- buf[127] = 0;
- sprintf(buf, cpufreq_sysfs_place_holder,0);
- scaling_gov = filp_open(buf, O_RDONLY, 0);
- if (scaling_gov != NULL) {
- if (scaling_gov->f_op != NULL &&
- scaling_gov->f_op->read != NULL)
- scaling_gov->f_op->read(scaling_gov,
- cpufreq_gov_default,
- 32,
- &offset);
- else
- pr_err("f_op might be null\n");
+ int ret = -EINVAL;
+ unsigned int cpu = 0;
- filp_close(scaling_gov, NULL);
- } else {
- pr_err("%s. Can't open %s\n", __func__, buf);
+#ifndef CONFIG_TEGRA_AUTO_HOTPLUG
+ for_each_online_cpu(cpu)
+#endif
+ {
+ ret = cpufreq_set_gov(target_gov, cpu);
+ if (ret < 0)
+ /* Unable to set gov for the online cpu.
+ * If it happens, needs to debug.
+ */
+ pr_info("Unable to set gov:%s for online cpu:%d,"
+ , cpufreq_default_gov[cpu]
+ , cpu);
}
- set_fs(old_fs);
}
-void cpufreq_restore_default_governor(void)
+void cpufreq_restore_default_gov(void)
{
- cpufreq_set_governor(cpufreq_gov_default);
-}
+ int ret = -EINVAL;
+ unsigned int cpu = 0;
-void cpufreq_set_conservative_governor_param(char *name, int value)
-{
- struct file *gov_param = NULL;
- mm_segment_t old_fs;
- static char buf[128], param_value[8];
- loff_t offset = 0;
-
- /* change to KERNEL_DS address limit */
- old_fs = get_fs();
- set_fs(KERNEL_DS);
-
- sprintf(param_value, "%d", value);
- sprintf(buf, cpufreq_gov_conservative_param, name);
- gov_param = filp_open(buf, O_RDWR, 0);
- if (gov_param != NULL) {
- if (gov_param->f_op != NULL &&
- gov_param->f_op->write != NULL)
- gov_param->f_op->write(gov_param,
- param_value,
- strlen(param_value),
- &offset);
- else
- pr_err("f_op might be null\n");
-
- filp_close(gov_param, NULL);
- } else {
- pr_err("%s. Can't open %s\n", __func__, buf);
+#ifndef CONFIG_TEGRA_AUTO_HOTPLUG
+ for_each_online_cpu(cpu)
+#endif
+ {
+ if (&cpufreq_default_gov[cpu] &&
+ strlen((const char *)&cpufreq_default_gov[cpu])) {
+ ret = cpufreq_set_gov(cpufreq_default_gov[cpu], cpu);
+ if (ret < 0)
+ /* Unable to restore gov for the cpu as
+ * It was online on suspend and becomes
+ * offline on resume.
+ */
+ pr_info("Unable to restore gov:%s for cpu:%d,"
+ , cpufreq_default_gov[cpu]
+ , cpu);
+ }
+ cpufreq_default_gov[cpu][0] = '\0';
}
- set_fs(old_fs);
-}
-
-void cpufreq_set_conservative_governor(void)
-{
- cpufreq_set_governor(cpufreq_gov_conservative);
}
#endif /* CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND */
diff --git a/arch/arm/mach-tegra/cpu-tegra.c b/arch/arm/mach-tegra/cpu-tegra.c
index d35c18e533d9..9bed9270b412 100644
--- a/arch/arm/mach-tegra/cpu-tegra.c
+++ b/arch/arm/mach-tegra/cpu-tegra.c
@@ -242,12 +242,12 @@ int tegra_edp_update_thermal_zone(int temperature)
/* Update cpu rate if cpufreq (at least on cpu0) is already started;
alter cpu dvfs table for this thermal zone if necessary */
- tegra_cpu_dvfs_alter(edp_thermal_index, true);
+ tegra_cpu_dvfs_alter(edp_thermal_index, &edp_cpumask, true);
if (target_cpu_speed[0]) {
edp_update_limit();
tegra_cpu_set_speed_cap(NULL);
}
- tegra_cpu_dvfs_alter(edp_thermal_index, false);
+ tegra_cpu_dvfs_alter(edp_thermal_index, &edp_cpumask, false);
mutex_unlock(&tegra_cpu_lock);
return ret;
@@ -321,6 +321,7 @@ static int tegra_cpu_edp_notify(
case CPU_UP_PREPARE:
mutex_lock(&tegra_cpu_lock);
cpu_set(cpu, edp_cpumask);
+ tegra_cpu_dvfs_alter(edp_thermal_index, &edp_cpumask, true);
edp_update_limit();
cpu_speed = tegra_getspeed(0);
@@ -335,13 +336,16 @@ static int tegra_cpu_edp_notify(
printk(KERN_DEBUG "tegra CPU:%sforce EDP limit %u kHz"
"\n", ret ? " failed to " : " ", new_speed);
}
+ tegra_cpu_dvfs_alter(edp_thermal_index, &edp_cpumask, false);
mutex_unlock(&tegra_cpu_lock);
break;
case CPU_DEAD:
mutex_lock(&tegra_cpu_lock);
cpu_clear(cpu, edp_cpumask);
+ tegra_cpu_dvfs_alter(edp_thermal_index, &edp_cpumask, true);
edp_update_limit();
tegra_cpu_set_speed_cap(NULL);
+ tegra_cpu_dvfs_alter(edp_thermal_index, &edp_cpumask, false);
mutex_unlock(&tegra_cpu_lock);
break;
}
@@ -431,9 +435,6 @@ static int __init tegra_cpu_debug_init(void)
if (!cpu_tegra_debugfs_root)
return -ENOMEM;
- if (tegra_throttle_debug_init(cpu_tegra_debugfs_root))
- goto err_out;
-
if (tegra_edp_debug_init(cpu_tegra_debugfs_root))
goto err_out;
@@ -469,7 +470,7 @@ unsigned int tegra_getspeed(unsigned int cpu)
return rate;
}
-static int tegra_update_cpu_speed(unsigned long rate)
+int tegra_update_cpu_speed(unsigned long rate)
{
int ret = 0;
struct cpufreq_freqs freqs;
diff --git a/arch/arm/mach-tegra/cpu-tegra.h b/arch/arm/mach-tegra/cpu-tegra.h
index 2bba460514f3..0dda294ea2cc 100644
--- a/arch/arm/mach-tegra/cpu-tegra.h
+++ b/arch/arm/mach-tegra/cpu-tegra.h
@@ -22,6 +22,7 @@
#define __MACH_TEGRA_CPU_TEGRA_H
unsigned int tegra_getspeed(unsigned int cpu);
+int tegra_update_cpu_speed(unsigned long rate);
int tegra_cpu_set_speed_cap(unsigned int *speed_cap);
unsigned int tegra_count_slow_cpus(unsigned long speed_limit);
unsigned int tegra_get_slowest_cpu_n(void);
diff --git a/arch/arm/mach-tegra/cpu-tegra3.c b/arch/arm/mach-tegra/cpu-tegra3.c
index b6579b6b5427..051381297f6f 100644
--- a/arch/arm/mach-tegra/cpu-tegra3.c
+++ b/arch/arm/mach-tegra/cpu-tegra3.c
@@ -41,7 +41,7 @@
#define INITIAL_STATE TEGRA_HP_DISABLED
#define UP2G0_DELAY_MS 70
#define UP2Gn_DELAY_MS 100
-#define DOWN_DELAY_MS 2000
+#define DOWN_DELAY_MS 500
static struct mutex *tegra3_cpu_lock;
@@ -66,13 +66,15 @@ module_param(idle_bottom_freq, uint, 0644);
static int mp_overhead = 10;
module_param(mp_overhead, int, 0644);
-static int balance_level = 75;
+static int balance_level = 60;
module_param(balance_level, int, 0644);
static struct clk *cpu_clk;
static struct clk *cpu_g_clk;
static struct clk *cpu_lp_clk;
+static unsigned long last_change_time;
+
static struct {
cputime64_t time_up_total;
u64 last_update;
@@ -186,6 +188,14 @@ enum {
TEGRA_CPU_SPEED_SKEWED,
};
+#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 noinline int tegra_cpu_speed_balance(void)
{
unsigned long highest_speed = tegra_cpu_highest_speed();
@@ -194,17 +204,36 @@ static noinline int tegra_cpu_speed_balance(void)
unsigned int nr_cpus = num_online_cpus();
unsigned int max_cpus = pm_qos_request(PM_QOS_MAX_ONLINE_CPUS) ? : 4;
unsigned int min_cpus = pm_qos_request(PM_QOS_MIN_ONLINE_CPUS);
+ unsigned int avg_nr_run = avg_nr_running();
+ unsigned int nr_run;
+
+ /* Evaluate:
+ * - distribution of freq targets for already on-lined CPUs
+ * - average number of runnable threads
+ * - effective MIPS available within EDP frequency limits,
+ * and return:
+ * TEGRA_CPU_SPEED_BALANCED to bring one more CPU core on-line
+ * TEGRA_CPU_SPEED_BIASED to keep CPU core composition unchanged
+ * TEGRA_CPU_SPEED_SKEWED to remove CPU core off-line
+ */
+ 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;
- /* 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 */
if (((tegra_count_slow_cpus(skewed_speed) >= 2) ||
+ (nr_run < nr_cpus) ||
tegra_cpu_edp_favor_down(nr_cpus, mp_overhead) ||
(highest_speed <= idle_bottom_freq) || (nr_cpus > max_cpus)) &&
(nr_cpus > min_cpus))
return TEGRA_CPU_SPEED_SKEWED;
if (((tegra_count_slow_cpus(balanced_speed) >= 1) ||
+ (nr_run <= nr_cpus) ||
(!tegra_cpu_edp_favor_up(nr_cpus, mp_overhead)) ||
(highest_speed <= idle_bottom_freq) || (nr_cpus == max_cpus)) &&
(nr_cpus >= min_cpus))
@@ -217,6 +246,7 @@ static void tegra_auto_hotplug_work_func(struct work_struct *work)
{
bool up = false;
unsigned int cpu = nr_cpu_ids;
+ unsigned long now = jiffies;
mutex_lock(tegra3_cpu_lock);
@@ -228,23 +258,24 @@ static void tegra_auto_hotplug_work_func(struct work_struct *work)
cpu = tegra_get_slowest_cpu_n();
if (cpu < nr_cpu_ids) {
up = false;
- queue_delayed_work(
- hotplug_wq, &hotplug_work, down_delay);
- hp_stats_update(cpu, false);
- } else if (!is_lp_cluster() && !no_lp) {
+ } else if (!is_lp_cluster() && !no_lp &&
+ !pm_qos_request(PM_QOS_MIN_ONLINE_CPUS) &&
+ ((now - last_change_time) >= down_delay)) {
if(!clk_set_parent(cpu_clk, cpu_lp_clk)) {
hp_stats_update(CONFIG_NR_CPUS, true);
hp_stats_update(0, false);
/* catch-up with governor target speed */
tegra_cpu_set_speed_cap(NULL);
- } else
- queue_delayed_work(
- hotplug_wq, &hotplug_work, down_delay);
+ break;
+ }
}
+ queue_delayed_work(
+ hotplug_wq, &hotplug_work, up2gn_delay);
break;
case TEGRA_HP_UP:
if (is_lp_cluster() && !no_lp) {
if(!clk_set_parent(cpu_clk, cpu_g_clk)) {
+ last_change_time = now;
hp_stats_update(CONFIG_NR_CPUS, false);
hp_stats_update(0, true);
/* catch-up with governor target speed */
@@ -255,18 +286,14 @@ static void tegra_auto_hotplug_work_func(struct work_struct *work)
/* cpu speed is up and balanced - one more on-line */
case TEGRA_CPU_SPEED_BALANCED:
cpu = cpumask_next_zero(0, cpu_online_mask);
- if (cpu < nr_cpu_ids) {
+ if (cpu < nr_cpu_ids)
up = true;
- hp_stats_update(cpu, true);
- }
break;
/* cpu speed is up, but skewed - remove one core */
case TEGRA_CPU_SPEED_SKEWED:
cpu = tegra_get_slowest_cpu_n();
- if (cpu < nr_cpu_ids) {
+ if (cpu < nr_cpu_ids)
up = false;
- hp_stats_update(cpu, false);
- }
break;
/* cpu speed is up, but under-utilized - do nothing */
case TEGRA_CPU_SPEED_BIASED:
@@ -281,6 +308,14 @@ static void tegra_auto_hotplug_work_func(struct work_struct *work)
pr_err("%s: invalid tegra hotplug state %d\n",
__func__, hp_state);
}
+
+ if (!up && ((now - last_change_time) < down_delay))
+ cpu = nr_cpu_ids;
+
+ if (cpu < nr_cpu_ids) {
+ last_change_time = now;
+ hp_stats_update(cpu, up);
+ }
mutex_unlock(tegra3_cpu_lock);
if (cpu < nr_cpu_ids) {
@@ -295,8 +330,14 @@ static int min_cpus_notify(struct notifier_block *nb, unsigned long n, void *p)
{
mutex_lock(tegra3_cpu_lock);
- if ((n >= 2) && is_lp_cluster()) {
+ if ((n >= 1) && is_lp_cluster()) {
+ /* make sure cpu rate is within g-mode range before switching */
+ unsigned int speed = max((unsigned long)tegra_getspeed(0),
+ clk_get_min_rate(cpu_g_clk) / 1000);
+ tegra_update_cpu_speed(speed);
+
if (!clk_set_parent(cpu_clk, cpu_g_clk)) {
+ last_change_time = jiffies;
hp_stats_update(CONFIG_NR_CPUS, false);
hp_stats_update(0, true);
}
@@ -318,7 +359,10 @@ void tegra_auto_hotplug_governor(unsigned int cpu_freq, bool suspend)
if (!is_g_cluster_present())
return;
- if (suspend && (hp_state != TEGRA_HP_DISABLED)) {
+ if (hp_state == TEGRA_HP_DISABLED)
+ return;
+
+ if (suspend) {
hp_state = TEGRA_HP_IDLE;
/* Switch to G-mode if suspend rate is high enough */
@@ -351,8 +395,6 @@ void tegra_auto_hotplug_governor(unsigned int cpu_freq, bool suspend)
}
switch (hp_state) {
- case TEGRA_HP_DISABLED:
- break;
case TEGRA_HP_IDLE:
if (cpu_freq > top_freq) {
hp_state = TEGRA_HP_UP;
@@ -361,7 +403,7 @@ void tegra_auto_hotplug_governor(unsigned int cpu_freq, bool suspend)
} else if (cpu_freq <= bottom_freq) {
hp_state = TEGRA_HP_DOWN;
queue_delayed_work(
- hotplug_wq, &hotplug_work, down_delay);
+ hotplug_wq, &hotplug_work, up_delay);
}
break;
case TEGRA_HP_DOWN:
@@ -377,7 +419,7 @@ void tegra_auto_hotplug_governor(unsigned int cpu_freq, bool suspend)
if (cpu_freq <= bottom_freq) {
hp_state = TEGRA_HP_DOWN;
queue_delayed_work(
- hotplug_wq, &hotplug_work, down_delay);
+ hotplug_wq, &hotplug_work, up_delay);
} else if (cpu_freq <= top_freq) {
hp_state = TEGRA_HP_IDLE;
}
diff --git a/arch/arm/mach-tegra/cpuquiet.c b/arch/arm/mach-tegra/cpuquiet.c
new file mode 100644
index 000000000000..26adce230920
--- /dev/null
+++ b/arch/arm/mach-tegra/cpuquiet.c
@@ -0,0 +1,433 @@
+/*
+ * arch/arm/mach-tegra/cpuquiet.c
+ *
+ * Cpuquiet driver for Tegra3 CPUs
+ *
+ * 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/types.h>
+#include <linux/sched.h>
+#include <linux/cpufreq.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/cpu.h>
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/pm_qos_params.h>
+#include <linux/cpuquiet.h>
+
+#include "pm.h"
+#include "cpu-tegra.h"
+#include "clock.h"
+
+#define INITIAL_STATE TEGRA_CPQ_IDLE
+#define UP_DELAY_MS 70
+#define DOWN_DELAY_MS 2000
+
+static struct mutex *tegra3_cpu_lock;
+static struct workqueue_struct *cpuquiet_wq;
+static struct delayed_work cpuquiet_work;
+static struct work_struct minmax_work;
+
+static struct kobject *tegra_auto_sysfs_kobject;
+
+static bool no_lp;
+static bool enable;
+static unsigned long up_delay;
+static unsigned long down_delay;
+static int mp_overhead = 10;
+static unsigned int idle_top_freq;
+static unsigned int idle_bottom_freq;
+
+static struct clk *cpu_clk;
+static struct clk *cpu_g_clk;
+static struct clk *cpu_lp_clk;
+
+static struct cpumask cr_online_requests;
+
+enum {
+ TEGRA_CPQ_DISABLED = 0,
+ TEGRA_CPQ_IDLE,
+ TEGRA_CPQ_SWITCH_TO_LP,
+ TEGRA_CPQ_SWITCH_TO_G,
+};
+
+static int cpq_state;
+
+static int update_core_config(unsigned int cpunumber, bool up)
+{
+ int ret = -EINVAL;
+ unsigned int nr_cpus = num_online_cpus();
+ int max_cpus = pm_qos_request(PM_QOS_MAX_ONLINE_CPUS) ? : 4;
+ int min_cpus = pm_qos_request(PM_QOS_MIN_ONLINE_CPUS);
+
+ if (cpq_state == TEGRA_CPQ_DISABLED || cpunumber >= nr_cpu_ids)
+ return ret;
+
+ if (up) {
+ if(is_lp_cluster()) {
+ cpumask_set_cpu(cpunumber, &cr_online_requests);
+ ret = -EBUSY;
+ } else {
+ if (tegra_cpu_edp_favor_up(nr_cpus, mp_overhead) &&
+ nr_cpus < max_cpus)
+ ret = cpu_up(cpunumber);
+ }
+ } else {
+ if (is_lp_cluster()) {
+ ret = -EBUSY;
+ } else {
+ if (nr_cpus > min_cpus)
+ ret = cpu_down(cpunumber);
+ }
+ }
+
+ return ret;
+}
+
+static int tegra_quiesence_cpu(unsigned int cpunumber)
+{
+ return update_core_config(cpunumber, false);
+}
+
+static int tegra_wake_cpu(unsigned int cpunumber)
+{
+ return update_core_config(cpunumber, true);
+}
+
+static struct cpuquiet_driver tegra_cpuquiet_driver = {
+ .name = "tegra",
+ .quiesence_cpu = tegra_quiesence_cpu,
+ .wake_cpu = tegra_wake_cpu,
+};
+
+static void apply_core_config(void)
+{
+ unsigned int cpu;
+
+ if (is_lp_cluster() || cpq_state == TEGRA_CPQ_DISABLED)
+ return;
+
+ for_each_cpu_mask(cpu, cr_online_requests) {
+ if (cpu < nr_cpu_ids && !cpu_online(cpu))
+ if (!tegra_wake_cpu(cpu))
+ cpumask_clear_cpu(cpu, &cr_online_requests);
+ }
+}
+
+static void tegra_cpuquiet_work_func(struct work_struct *work)
+{
+ bool update_cr_config = false;
+
+ mutex_lock(tegra3_cpu_lock);
+
+ switch(cpq_state) {
+ case TEGRA_CPQ_DISABLED:
+ case TEGRA_CPQ_IDLE:
+ break;
+ case TEGRA_CPQ_SWITCH_TO_G:
+ if (is_lp_cluster()) {
+ if(!clk_set_parent(cpu_clk, cpu_g_clk)) {
+ /*catch-up with governor target speed */
+ tegra_cpu_set_speed_cap(NULL);
+ /* process pending core requests*/
+ update_cr_config = true;
+ }
+ }
+ break;
+ case TEGRA_CPQ_SWITCH_TO_LP:
+ if (!is_lp_cluster() && !no_lp &&
+ !pm_qos_request(PM_QOS_MIN_ONLINE_CPUS)
+ && num_online_cpus() == 1) {
+ if (!clk_set_parent(cpu_clk, cpu_lp_clk)) {
+ /*catch-up with governor target speed*/
+ tegra_cpu_set_speed_cap(NULL);
+ }
+ }
+ break;
+ default:
+ pr_err("%s: invalid tegra hotplug state %d\n",
+ __func__, cpq_state);
+ }
+
+ mutex_unlock(tegra3_cpu_lock);
+
+ if (update_cr_config)
+ apply_core_config();
+}
+
+static void min_max_constraints_workfunc(struct work_struct *work)
+{
+ int count = -1;
+ bool up = false;
+ unsigned int cpu;
+
+ int nr_cpus = num_online_cpus();
+ int max_cpus = pm_qos_request(PM_QOS_MAX_ONLINE_CPUS) ? : 4;
+ int min_cpus = pm_qos_request(PM_QOS_MIN_ONLINE_CPUS);
+
+ if (is_lp_cluster())
+ return;
+
+ if (nr_cpus < min_cpus) {
+ up = true;
+ count = min_cpus - nr_cpus;
+ } else if (nr_cpus > max_cpus && max_cpus >= min_cpus) {
+ count = nr_cpus - max_cpus;
+ }
+
+ for (;count > 0; count--) {
+ if (up) {
+ cpu = cpumask_next_zero(0, cpu_online_mask);
+ if (cpu < nr_cpu_ids)
+ cpu_up(cpu);
+ else
+ break;
+ } else {
+ cpu = cpumask_next(0, cpu_online_mask);
+ if (cpu < nr_cpu_ids)
+ cpu_down(cpu);
+ else
+ break;
+ }
+ }
+}
+
+static int min_cpus_notify(struct notifier_block *nb, unsigned long n, void *p)
+{
+ mutex_lock(tegra3_cpu_lock);
+
+ if ((n >= 1) && is_lp_cluster()) {
+ /* make sure cpu rate is within g-mode range before switching */
+ unsigned long speed = max((unsigned long)tegra_getspeed(0),
+ clk_get_min_rate(cpu_g_clk) / 1000);
+ tegra_update_cpu_speed(speed);
+
+ clk_set_parent(cpu_clk, cpu_g_clk);
+ }
+
+ tegra_cpu_set_speed_cap(NULL);
+ mutex_unlock(tegra3_cpu_lock);
+
+ schedule_work(&minmax_work);
+
+ return NOTIFY_OK;
+}
+
+static int max_cpus_notify(struct notifier_block *nb, unsigned long n, void *p)
+{
+ if (n < num_online_cpus())
+ schedule_work(&minmax_work);
+
+ return NOTIFY_OK;
+}
+
+void tegra_auto_hotplug_governor(unsigned int cpu_freq, bool suspend)
+{
+ if (!is_g_cluster_present())
+ return;
+
+ if (cpq_state == TEGRA_CPQ_DISABLED)
+ return;
+
+ if (suspend) {
+ cpq_state = TEGRA_CPQ_IDLE;
+
+ /* Switch to G-mode if suspend rate is high enough */
+ if (is_lp_cluster() && (cpu_freq >= idle_bottom_freq)) {
+ clk_set_parent(cpu_clk, cpu_g_clk);
+ }
+ return;
+ }
+
+ if (is_lp_cluster() && pm_qos_request(PM_QOS_MIN_ONLINE_CPUS) >= 2) {
+ if (cpq_state != TEGRA_CPQ_SWITCH_TO_G) {
+ /* Force switch */
+ cpq_state = TEGRA_CPQ_SWITCH_TO_G;
+ queue_delayed_work(
+ cpuquiet_wq, &cpuquiet_work, up_delay);
+ }
+ return;
+ }
+
+ if (is_lp_cluster() && (cpu_freq >= idle_top_freq || no_lp)) {
+ cpq_state = TEGRA_CPQ_SWITCH_TO_G;
+ queue_delayed_work(cpuquiet_wq, &cpuquiet_work, up_delay);
+ } else if (!is_lp_cluster() && !no_lp &&
+ cpu_freq <= idle_bottom_freq) {
+ cpq_state = TEGRA_CPQ_SWITCH_TO_LP;
+ queue_delayed_work(cpuquiet_wq, &cpuquiet_work, down_delay);
+ } else {
+ cpq_state = TEGRA_CPQ_IDLE;
+ }
+}
+
+static struct notifier_block min_cpus_notifier = {
+ .notifier_call = min_cpus_notify,
+};
+
+static struct notifier_block max_cpus_notifier = {
+ .notifier_call = max_cpus_notify,
+};
+
+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);
+ }
+}
+
+static void enable_callback(struct cpuquiet_attribute *attr)
+{
+ mutex_lock(tegra3_cpu_lock);
+
+ if (!enable && cpq_state != TEGRA_CPQ_DISABLED) {
+ cpq_state = TEGRA_CPQ_DISABLED;
+ mutex_unlock(tegra3_cpu_lock);
+ cancel_delayed_work_sync(&cpuquiet_work);
+ pr_info("Tegra cpuquiet clusterswitch disabled\n");
+ mutex_lock(tegra3_cpu_lock);
+ } else if (enable && cpq_state == TEGRA_CPQ_DISABLED) {
+ cpq_state = TEGRA_CPQ_IDLE;
+ pr_info("Tegra cpuquiet clusterswitch enabled\n");
+ tegra_cpu_set_speed_cap(NULL);
+ }
+
+ mutex_unlock(tegra3_cpu_lock);
+}
+
+CPQ_BASIC_ATTRIBUTE(no_lp, 0644, bool);
+CPQ_BASIC_ATTRIBUTE(idle_top_freq, 0644, uint);
+CPQ_BASIC_ATTRIBUTE(idle_bottom_freq, 0644, uint);
+CPQ_BASIC_ATTRIBUTE(mp_overhead, 0644, int);
+CPQ_ATTRIBUTE(up_delay, 0644, ulong, delay_callback);
+CPQ_ATTRIBUTE(down_delay, 0644, ulong, delay_callback);
+CPQ_ATTRIBUTE(enable, 0644, bool, enable_callback);
+
+static struct attribute *tegra_auto_attributes[] = {
+ &no_lp_attr.attr,
+ &up_delay_attr.attr,
+ &down_delay_attr.attr,
+ &idle_top_freq_attr.attr,
+ &idle_bottom_freq_attr.attr,
+ &mp_overhead_attr.attr,
+ &enable_attr.attr,
+ NULL,
+};
+
+static const struct sysfs_ops tegra_auto_sysfs_ops = {
+ .show = cpuquiet_auto_sysfs_show,
+ .store = cpuquiet_auto_sysfs_store,
+};
+
+static struct kobj_type ktype_sysfs = {
+ .sysfs_ops = &tegra_auto_sysfs_ops,
+ .default_attrs = tegra_auto_attributes,
+};
+
+static int tegra_auto_sysfs(void)
+{
+ int err;
+
+ tegra_auto_sysfs_kobject = kzalloc(sizeof(*tegra_auto_sysfs_kobject),
+ GFP_KERNEL);
+
+ if (!tegra_auto_sysfs_kobject)
+ return -ENOMEM;
+
+ err = cpuquiet_kobject_init(tegra_auto_sysfs_kobject, &ktype_sysfs,
+ "tegra_cpuquiet");
+
+ if (err)
+ kfree(tegra_auto_sysfs_kobject);
+
+ return err;
+}
+
+int tegra_auto_hotplug_init(struct mutex *cpu_lock)
+{
+ int err;
+
+ cpu_clk = clk_get_sys(NULL, "cpu");
+ cpu_g_clk = clk_get_sys(NULL, "cpu_g");
+ cpu_lp_clk = clk_get_sys(NULL, "cpu_lp");
+
+ if (IS_ERR(cpu_clk) || IS_ERR(cpu_g_clk) || IS_ERR(cpu_lp_clk))
+ return -ENOENT;
+
+ /*
+ * Not bound to the issuer CPU (=> high-priority), has rescue worker
+ * task, single-threaded, freezable.
+ */
+ cpuquiet_wq = alloc_workqueue(
+ "cpuquiet", WQ_UNBOUND | WQ_RESCUER | WQ_FREEZABLE, 1);
+
+ if (!cpuquiet_wq)
+ return -ENOMEM;
+
+ INIT_DELAYED_WORK(&cpuquiet_work, tegra_cpuquiet_work_func);
+ INIT_WORK(&minmax_work, min_max_constraints_workfunc);
+
+ idle_top_freq = clk_get_max_rate(cpu_lp_clk) / 1000;
+ idle_bottom_freq = clk_get_min_rate(cpu_g_clk) / 1000;
+
+ up_delay = msecs_to_jiffies(UP_DELAY_MS);
+ down_delay = msecs_to_jiffies(DOWN_DELAY_MS);
+ cpumask_clear(&cr_online_requests);
+ tegra3_cpu_lock = cpu_lock;
+
+ cpq_state = INITIAL_STATE;
+ enable = cpq_state == TEGRA_CPQ_DISABLED ? false : true;
+
+
+ pr_info("Tegra cpuquiet initialized: %s\n",
+ (cpq_state == TEGRA_CPQ_DISABLED) ? "disabled" : "enabled");
+
+ if (pm_qos_add_notifier(PM_QOS_MIN_ONLINE_CPUS, &min_cpus_notifier))
+ pr_err("%s: Failed to register min cpus PM QoS notifier\n",
+ __func__);
+ if (pm_qos_add_notifier(PM_QOS_MAX_ONLINE_CPUS, &max_cpus_notifier))
+ pr_err("%s: Failed to register max cpus PM QoS notifier\n",
+ __func__);
+
+ err = cpuquiet_register_driver(&tegra_cpuquiet_driver);
+ if (err) {
+ destroy_workqueue(cpuquiet_wq);
+ return err;
+ }
+
+ err = tegra_auto_sysfs();
+ if (err) {
+ cpuquiet_unregister_driver(&tegra_cpuquiet_driver);
+ destroy_workqueue(cpuquiet_wq);
+ }
+
+ return err;
+}
+
+void tegra_auto_hotplug_exit(void)
+{
+ destroy_workqueue(cpuquiet_wq);
+ cpuquiet_unregister_driver(&tegra_cpuquiet_driver);
+ kobject_put(tegra_auto_sysfs_kobject);
+}
diff --git a/arch/arm/mach-tegra/devices.c b/arch/arm/mach-tegra/devices.c
index 079d18e2339b..79f3ccc57f92 100644
--- a/arch/arm/mach-tegra/devices.c
+++ b/arch/arm/mach-tegra/devices.c
@@ -584,28 +584,6 @@ static struct resource tegra_usb3_resources[] = {
},
};
-static struct tegra_ulpi_config tegra_ehci2_ulpi_phy_config = {
- /* All existing boards use GPIO PV0 for phy reset */
- .reset_gpio = TEGRA_GPIO_PV0,
- .clk = "cdev2",
-};
-
-static struct tegra_ehci_platform_data tegra_ehci1_pdata = {
- .operating_mode = TEGRA_USB_OTG,
- .power_down_on_bus_suspend = 1,
-};
-
-static struct tegra_ehci_platform_data tegra_ehci2_pdata = {
- .phy_config = &tegra_ehci2_ulpi_phy_config,
- .operating_mode = TEGRA_USB_HOST,
- .power_down_on_bus_suspend = 1,
-};
-
-static struct tegra_ehci_platform_data tegra_ehci3_pdata = {
- .operating_mode = TEGRA_USB_HOST,
- .power_down_on_bus_suspend = 1,
-};
-
static u64 tegra_ehci_dmamask = DMA_BIT_MASK(32);
struct platform_device tegra_ehci1_device = {
@@ -614,7 +592,6 @@ struct platform_device tegra_ehci1_device = {
.dev = {
.dma_mask = &tegra_ehci_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &tegra_ehci1_pdata,
},
.resource = tegra_usb1_resources,
.num_resources = ARRAY_SIZE(tegra_usb1_resources),
@@ -626,7 +603,6 @@ struct platform_device tegra_ehci2_device = {
.dev = {
.dma_mask = &tegra_ehci_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &tegra_ehci2_pdata,
},
.resource = tegra_usb2_resources,
.num_resources = ARRAY_SIZE(tegra_usb2_resources),
@@ -638,7 +614,6 @@ struct platform_device tegra_ehci3_device = {
.dev = {
.dma_mask = &tegra_ehci_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &tegra_ehci3_pdata,
},
.resource = tegra_usb3_resources,
.num_resources = ARRAY_SIZE(tegra_usb3_resources),
@@ -1216,6 +1191,11 @@ struct platform_device tegra_pcm_device = {
.id = -1,
};
+struct platform_device tegra_tdm_pcm_device = {
+ .name = "tegra-tdm-pcm-audio",
+ .id = -1,
+};
+
static struct resource w1_resources[] = {
[0] = {
.start = INT_OWR,
@@ -1251,18 +1231,12 @@ static struct resource tegra_udc_resources[] = {
static u64 tegra_udc_dmamask = DMA_BIT_MASK(32);
-static struct fsl_usb2_platform_data tegra_udc_pdata = {
- .operating_mode = FSL_USB2_DR_DEVICE,
- .phy_mode = FSL_USB2_PHY_UTMI,
-};
-
struct platform_device tegra_udc_device = {
- .name = "fsl-tegra-udc",
- .id = -1,
+ .name = "tegra-udc",
+ .id = 0,
.dev = {
.dma_mask = &tegra_udc_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &tegra_udc_pdata,
},
.resource = tegra_udc_resources,
.num_resources = ARRAY_SIZE(tegra_udc_resources),
@@ -1424,16 +1398,23 @@ static struct resource tegra_wdt_resources[] = {
.flags = IORESOURCE_IRQ,
},
};
+
+struct platform_device tegra_wdt_device = {
+ .name = "tegra_wdt",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(tegra_wdt_resources),
+ .resource = tegra_wdt_resources,
+};
#else
-static struct resource tegra_wdt_resources[] = {
+static struct resource tegra_wdt0_resources[] = {
[0] = {
.start = TEGRA_WDT0_BASE,
.end = TEGRA_WDT0_BASE + TEGRA_WDT0_SIZE - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = TEGRA_TMR10_BASE,
- .end = TEGRA_TMR10_BASE + TEGRA_TMR10_SIZE - 1,
+ .start = TEGRA_TMR7_BASE,
+ .end = TEGRA_TMR7_BASE + TEGRA_TMR7_SIZE - 1,
.flags = IORESOURCE_MEM,
},
[2] = {
@@ -1441,16 +1422,64 @@ static struct resource tegra_wdt_resources[] = {
.end = INT_WDT_CPU,
.flags = IORESOURCE_IRQ,
},
-};
+#ifdef CONFIG_TEGRA_FIQ_DEBUGGER
+ [3] = {
+ .start = TEGRA_QUATERNARY_ICTLR_BASE,
+ .end = TEGRA_QUATERNARY_ICTLR_BASE + \
+ TEGRA_QUATERNARY_ICTLR_SIZE -1,
+ .flags = IORESOURCE_MEM,
+ },
#endif
+};
-struct platform_device tegra_wdt_device = {
+static struct resource tegra_wdt1_resources[] = {
+ [0] = {
+ .start = TEGRA_WDT1_BASE,
+ .end = TEGRA_WDT1_BASE + TEGRA_WDT1_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = TEGRA_TMR8_BASE,
+ .end = TEGRA_TMR8_BASE + TEGRA_TMR8_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct resource tegra_wdt2_resources[] = {
+ [0] = {
+ .start = TEGRA_WDT2_BASE,
+ .end = TEGRA_WDT2_BASE + TEGRA_WDT2_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = TEGRA_TMR9_BASE,
+ .end = TEGRA_TMR9_BASE + TEGRA_TMR9_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct platform_device tegra_wdt0_device = {
.name = "tegra_wdt",
- .id = -1,
- .num_resources = ARRAY_SIZE(tegra_wdt_resources),
- .resource = tegra_wdt_resources,
+ .id = 0,
+ .num_resources = ARRAY_SIZE(tegra_wdt0_resources),
+ .resource = tegra_wdt0_resources,
+};
+
+struct platform_device tegra_wdt1_device = {
+ .name = "tegra_wdt",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(tegra_wdt1_resources),
+ .resource = tegra_wdt1_resources,
};
+struct platform_device tegra_wdt2_device = {
+ .name = "tegra_wdt",
+ .id = 2,
+ .num_resources = ARRAY_SIZE(tegra_wdt2_resources),
+ .resource = tegra_wdt2_resources,
+};
+#endif
+
static struct resource tegra_pwfm0_resource = {
.start = TEGRA_PWFM0_BASE,
.end = TEGRA_PWFM0_BASE + TEGRA_PWFM0_SIZE - 1,
@@ -1699,6 +1728,28 @@ struct platform_device tegra_nvmap_device = {
.id = -1,
};
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+static struct resource tegra_cec_resources[] = {
+ [0] = {
+ .start = TEGRA_CEC_BASE,
+ .end = TEGRA_CEC_BASE + TEGRA_CEC_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = INT_CEC,
+ .end = INT_CEC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device tegra_cec_device = {
+ .name = "tegra_cec",
+ .id = -1,
+ .resource = tegra_cec_resources,
+ .num_resources = ARRAY_SIZE(tegra_cec_resources),
+};
+#endif
+
void __init tegra_init_debug_uart_rate(void)
{
unsigned int uartclk;
diff --git a/arch/arm/mach-tegra/devices.h b/arch/arm/mach-tegra/devices.h
index 8b413d45d9b9..c5cf7b708ec4 100644
--- a/arch/arm/mach-tegra/devices.h
+++ b/arch/arm/mach-tegra/devices.h
@@ -69,6 +69,7 @@ extern struct platform_device spdif_dit_device;
extern struct platform_device bluetooth_dit_device;
extern struct platform_device baseband_dit_device;
extern struct platform_device tegra_pcm_device;
+extern struct platform_device tegra_tdm_pcm_device;
extern struct platform_device tegra_w1_device;
extern struct platform_device tegra_udc_device;
extern struct platform_device tegra_ehci1_device;
@@ -97,7 +98,13 @@ extern struct platform_device tegra_gart_device;
#else
extern struct platform_device tegra_smmu_device;
#endif
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
extern struct platform_device tegra_wdt_device;
+#else
+extern struct platform_device tegra_wdt0_device;
+extern struct platform_device tegra_wdt1_device;
+extern struct platform_device tegra_wdt2_device;
+#endif
extern struct platform_device tegra_pwfm0_device;
extern struct platform_device tegra_pwfm1_device;
extern struct platform_device tegra_pwfm2_device;
@@ -109,7 +116,6 @@ extern struct platform_device tegra_uartc_device;
extern struct platform_device tegra_uartd_device;
extern struct platform_device tegra_uarte_device;
extern struct platform_device tegra_avp_device;
-extern struct nvhost_device tegra_grhost_device;
extern struct nvhost_device nvavp_device;
extern struct platform_device tegra_aes_device;
#if !defined(CONFIG_ARCH_TEGRA_2x_SOC)
@@ -127,6 +133,9 @@ extern struct platform_device debug_uarte_device;
extern struct nvhost_device tegra_disp1_device;
extern struct platform_device tegra_nvmap_device;
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+extern struct platform_device tegra_cec_device;
+#endif
void __init tegra_init_debug_uart_rate(void);
diff --git a/arch/arm/mach-tegra/dvfs.c b/arch/arm/mach-tegra/dvfs.c
index 8723e6fa60df..cb33e3db862f 100644
--- a/arch/arm/mach-tegra/dvfs.c
+++ b/arch/arm/mach-tegra/dvfs.c
@@ -322,8 +322,7 @@ static int dvfs_rail_connect_to_regulator(struct dvfs_rail *rail)
static inline unsigned long *dvfs_get_freqs(struct dvfs *d)
{
- return (d->alt_freqs_state == ALT_FREQS_ENABLED) ?
- &d->alt_freqs[0] : &d->freqs[0];
+ return d->alt_freqs ? : &d->freqs[0];
}
static int
@@ -367,26 +366,16 @@ __tegra_dvfs_set_rate(struct dvfs *d, unsigned long rate)
return ret;
}
-static inline int dvfs_alt_freqs_set(struct dvfs *d, bool enable)
+int tegra_dvfs_alt_freqs_set(struct dvfs *d, unsigned long *alt_freqs)
{
- if (d->alt_freqs_state == ALT_FREQS_NOT_SUPPORTED)
- return -ENOSYS;
-
- d->alt_freqs_state = enable ? ALT_FREQS_ENABLED : ALT_FREQS_DISABLED;
- return 0;
-}
-
-int tegra_dvfs_alt_freqs_set(struct dvfs *d, bool enable)
-{
- int ret;
- enum dvfs_alt_freqs old_state;
+ int ret = 0;
mutex_lock(&dvfs_lock);
- old_state = d->alt_freqs_state;
- ret = dvfs_alt_freqs_set(d, enable);
- if (!ret && (old_state != d->alt_freqs_state))
+ if (d->alt_freqs != alt_freqs) {
+ d->alt_freqs = alt_freqs;
ret = __tegra_dvfs_set_rate(d, d->cur_rate);
+ }
mutex_unlock(&dvfs_lock);
return ret;
@@ -407,7 +396,7 @@ int tegra_dvfs_predict_millivolts(struct clk *c, unsigned long rate)
* frequency limits. For now, just fail the call for clock that has
* alternative limits initialized.
*/
- if (c->dvfs->alt_freqs_state != ALT_FREQS_NOT_SUPPORTED)
+ if (c->dvfs->alt_freqs)
return -ENOSYS;
for (i = 0; i < c->dvfs->num_freqs; i++) {
diff --git a/arch/arm/mach-tegra/dvfs.h b/arch/arm/mach-tegra/dvfs.h
index eaecf425fe87..3bdb13690278 100644
--- a/arch/arm/mach-tegra/dvfs.h
+++ b/arch/arm/mach-tegra/dvfs.h
@@ -21,7 +21,7 @@
#ifndef _TEGRA_DVFS_H_
#define _TEGRA_DVFS_H_
-#define MAX_DVFS_FREQS 18
+#define MAX_DVFS_FREQS 20
#define DVFS_RAIL_STATS_TOP_BIN 40
struct clk;
@@ -73,12 +73,6 @@ struct dvfs_rail {
struct rail_stats stats;
};
-enum dvfs_alt_freqs {
- ALT_FREQS_NOT_SUPPORTED = 0,
- ALT_FREQS_DISABLED,
- ALT_FREQS_ENABLED,
-};
-
struct dvfs {
/* Used only by tegra2_clock.c */
const char *clk_name;
@@ -88,11 +82,10 @@ struct dvfs {
/* Must be initialized before tegra_dvfs_init */
int freqs_mult;
unsigned long freqs[MAX_DVFS_FREQS];
- unsigned long alt_freqs[MAX_DVFS_FREQS];
+ unsigned long *alt_freqs;
const int *millivolts;
struct dvfs_rail *dvfs_rail;
bool auto_dvfs;
- enum dvfs_alt_freqs alt_freqs_state;
/* Filled in by tegra_dvfs_init */
int max_millivolts;
@@ -124,8 +117,9 @@ struct dvfs_rail *tegra_dvfs_get_rail_by_name(const char *reg_id);
int tegra_dvfs_predict_millivolts(struct clk *c, unsigned long rate);
void tegra_dvfs_core_cap_enable(bool enable);
void tegra_dvfs_core_cap_level_set(int level);
-int tegra_dvfs_alt_freqs_set(struct dvfs *d, bool enable);
-void tegra_cpu_dvfs_alter(int edp_thermal_index, bool before_clk_update);
+int tegra_dvfs_alt_freqs_set(struct dvfs *d, unsigned long *alt_freqs);
+void tegra_cpu_dvfs_alter(
+ int edp_thermal_index, const cpumask_t *cpus, bool before_clk_update);
#else
static inline void tegra_soc_init_dvfs(void)
{}
@@ -160,10 +154,11 @@ static inline void tegra_dvfs_core_cap_enable(bool enable)
{}
static inline void tegra_dvfs_core_cap_level_set(int level)
{}
-static inline int tegra_dvfs_alt_freqs_set(struct dvfs *d, bool enable)
+static inline int tegra_dvfs_alt_freqs_set(struct dvfs *d,
+ unsigned long *alt_freqs)
{ return 0; }
-static inline void tegra_cpu_dvfs_alter(int edp_thermal_index,
- bool before_clk_update)
+static inline void tegra_cpu_dvfs_alter(
+ int edp_thermal_index, const cpumask_t *cpus, bool before_clk_update)
{}
#endif
diff --git a/arch/arm/mach-tegra/headsmp.S b/arch/arm/mach-tegra/headsmp.S
index 4a9f03ffd972..4e28a558cc38 100644
--- a/arch/arm/mach-tegra/headsmp.S
+++ b/arch/arm/mach-tegra/headsmp.S
@@ -83,7 +83,9 @@ ENTRY(tegra_resume)
ldr r1, [r0]
orr r1, r1, #1
#if defined(CONFIG_HAVE_ARM_SCU)
- orr r1, r1, #(1 << 3) @ Enabled SCU speculative line fill.
+ orr r1, r1, #(1 << 3) @ Enable SCU speculative line fill.
+ orr r1, r1, #(1 << 5) @ Enable IC standby.
+ orr r1, r1, #(1 << 6) @ Enable SCU standby.
#endif
str r1, [r0]
diff --git a/arch/arm/mach-tegra/include/mach/clk.h b/arch/arm/mach-tegra/include/mach/clk.h
index 0fbbf24d5959..01d322a448d1 100644
--- a/arch/arm/mach-tegra/include/mach/clk.h
+++ b/arch/arm/mach-tegra/include/mach/clk.h
@@ -6,7 +6,7 @@
* Author:
* Erik Gilling <konkers@google.com>
*
- * Copyright (C) 2010-2011 NVIDIA Corporation
+ * 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
@@ -47,10 +47,20 @@ static inline int tegra_dvfs_set_rate(struct clk *c, unsigned long rate)
unsigned long clk_get_rate_all_locked(struct clk *c);
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
void tegra_sdmmc_tap_delay(struct clk *c, int delay);
+
+static inline int tegra_emc_enable_eack(void) {
+ return 0;
+}
+
+static inline int tegra_emc_disable_eack(void) {
+ return 0;
+}
#else
static inline void tegra_sdmmc_tap_delay(struct clk *c, int delay)
{
}
+int tegra_emc_enable_eack(void);
+int tegra_emc_disable_eack(void);
#endif
int tegra_dvfs_rail_disable_by_name(const char *reg_id);
int tegra_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting);
diff --git a/arch/arm/mach-tegra/include/mach/dc.h b/arch/arm/mach-tegra/include/mach/dc.h
index 3b9b431dea82..97f02ce6e95d 100644
--- a/arch/arm/mach-tegra/include/mach/dc.h
+++ b/arch/arm/mach-tegra/include/mach/dc.h
@@ -128,6 +128,13 @@ struct dsi_phy_timing_ns {
u16 t_tago_ns;
};
+/* Aggressiveness level of DSI suspend. The higher, the more aggressive. */
+#define DSI_NO_SUSPEND 0
+#define DSI_HOST_SUSPEND_LV0 1
+#define DSI_HOST_SUSPEND_LV1 2
+#define DSI_HOST_SUSPEND_LV2 3
+#define DSI_SUSPEND_FULL 4
+
struct tegra_dsi_out {
u8 n_data_lanes; /* required */
u8 pixel_format; /* required */
@@ -140,6 +147,7 @@ struct tegra_dsi_out {
u8 chip_rev;
bool panel_has_frame_buffer; /* required*/
+ bool panel_send_dc_frames;
struct tegra_dsi_cmd *dsi_init_cmd; /* required */
u16 n_init_cmd; /* required */
@@ -157,6 +165,8 @@ struct tegra_dsi_out {
u8 video_clock_mode;
u8 video_burst_mode;
+ u8 suspend_aggr;
+
u16 panel_buffer_size_byte;
u16 panel_reset_timeout_msec;
@@ -361,6 +371,7 @@ struct tegra_dc_out {
int (*enable)(void);
int (*postpoweron)(void);
+ int (*prepoweroff)(void);
int (*disable)(void);
int (*hotplug_init)(void);
@@ -377,6 +388,7 @@ struct tegra_dc_out {
#define TEGRA_DC_OUT_CONTINUOUS_MODE (0 << 3)
#define TEGRA_DC_OUT_ONE_SHOT_MODE (1 << 3)
#define TEGRA_DC_OUT_N_SHOT_MODE (1 << 4)
+#define TEGRA_DC_OUT_ONE_SHOT_LP_MODE (1 << 5)
#define TEGRA_DC_ALIGN_MSB 0
#define TEGRA_DC_ALIGN_LSB 1
@@ -384,6 +396,9 @@ struct tegra_dc_out {
#define TEGRA_DC_ORDER_RED_BLUE 0
#define TEGRA_DC_ORDER_BLUE_RED 1
+#define V_BLANK_FLIP 0
+#define V_BLANK_NVSD 1
+
struct tegra_dc;
struct nvmap_handle_ref;
@@ -426,6 +441,7 @@ struct tegra_dc_win {
unsigned out_w;
unsigned out_h;
unsigned z;
+ u8 global_alpha;
struct tegra_dc_csc csc;
@@ -502,6 +518,7 @@ struct tegra_dc_platform_data {
#define TEGRA_DC_FLAG_ENABLED (1 << 0)
+int tegra_dc_get_stride(struct tegra_dc *dc, unsigned win);
struct tegra_dc *tegra_dc_get_dc(unsigned idx);
struct tegra_dc_win *tegra_dc_get_window(struct tegra_dc *dc, unsigned win);
bool tegra_dc_get_connected(struct tegra_dc *);
@@ -538,7 +555,6 @@ unsigned tegra_dc_get_out_max_pixclock(const struct tegra_dc *dc);
struct tegra_dc_pwm_params {
int which_pwm;
- void (*switch_to_sfio)(int);
int gpio_conf_to_sfio;
unsigned int period;
unsigned int clk_div;
@@ -549,7 +565,10 @@ struct tegra_dc_pwm_params {
void tegra_dc_config_pwm(struct tegra_dc *dc, struct tegra_dc_pwm_params *cfg);
int tegra_dsi_send_panel_short_cmd(struct tegra_dc *dc, u8 *pdata, u8 data_len);
-void tegra_dc_host_trigger(struct tegra_dc *dc);
+void tegra_dc_host_suspend(struct tegra_dc *dc);
+void tegra_dc_host_resume(struct tegra_dc *dc);
+int tegra_dsi_host_suspend(struct tegra_dc *dc);
+int tegra_dsi_host_resume(struct tegra_dc *dc);
int tegra_dc_update_csc(struct tegra_dc *dc, int win_index);
diff --git a/arch/arm/mach-tegra/include/mach/iomap.h b/arch/arm/mach-tegra/include/mach/iomap.h
index c491abafb8b9..2e205db063dd 100644
--- a/arch/arm/mach-tegra/include/mach/iomap.h
+++ b/arch/arm/mach-tegra/include/mach/iomap.h
@@ -2,7 +2,7 @@
* arch/arm/mach-tegra/include/mach/iomap.h
*
* Copyright (C) 2010 Google, Inc.
- * Copyright (C) 2011 NVIDIA Corporation.
+ * Copyright (C) 2011-2012, NVIDIA Corporation.
*
* Author:
* Colin Cross <ccross@google.com>
@@ -92,6 +92,8 @@
#define TEGRA_GART_BASE 0x58000000
#define TEGRA_GART_SIZE SZ_32M
+#define TEGRA_IOMMU_BASE TEGRA_GART_BASE
+#define TEGRA_IOMMU_SIZE TEGRA_GART_SIZE
#else
@@ -99,6 +101,8 @@
#define TEGRA_SMMU_SIZE_TEGRA3_A01 SZ_256M
#define TEGRA_SMMU_BASE 0x00001000
#define TEGRA_SMMU_SIZE (SZ_1G - SZ_4K * 2)
+#define TEGRA_IOMMU_BASE TEGRA_SMMU_BASE
+#define TEGRA_IOMMU_SIZE TEGRA_SMMU_SIZE
#endif
@@ -263,6 +267,9 @@
#define TEGRA_TSENSOR_BASE 0x70014000
#define TEGRA_TSENSOR_SIZE SZ_4K
+#define TEGRA_CEC_BASE 0x70015000
+#define TEGRA_CEC_SIZE SZ_4K
+
#define TEGRA_HDA_BASE 0x70030000
#define TEGRA_HDA_SIZE SZ_64K
diff --git a/arch/arm/mach-tegra/include/mach/iovmm.h b/arch/arm/mach-tegra/include/mach/iovmm.h
index fd83a326e129..cd56bd835592 100644
--- a/arch/arm/mach-tegra/include/mach/iovmm.h
+++ b/arch/arm/mach-tegra/include/mach/iovmm.h
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/include/mach/iovmm.h
*
- * 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
@@ -68,6 +68,8 @@ struct tegra_iovmm_domain {
struct iovmm_share_group;
+#if !defined(CONFIG_IOMMU_API)
+
struct tegra_iovmm_client {
const char *name;
unsigned long flags;
@@ -90,6 +92,25 @@ struct tegra_iovmm_area {
struct tegra_iovmm_area_ops *ops;
};
+#else /* CONFIG_IOMMU_API */
+
+/*
+ * To replace IOVMM with IOMMU backend
+ */
+
+struct tegra_iovmm_client {
+ struct device *dev;
+};
+
+struct tegra_iovmm_area {
+ dma_addr_t iovm_start;
+ size_t iovm_length;
+ pgprot_t pgprot;
+ struct device *dev;
+};
+
+#endif /* CONFIG_IOMMU_API */
+
struct tegra_iovmm_device_ops {
/* maps a VMA using the page residency functions provided by the VMA */
int (*map)(struct tegra_iovmm_domain *domain,
@@ -140,9 +161,16 @@ struct tegra_iovmm_area_ops {
* called by clients to allocate an I/O VMM client mapping context which
* will be shared by all clients in the same share_group
*/
-struct tegra_iovmm_client *tegra_iovmm_alloc_client(const char *name,
+struct tegra_iovmm_client *__tegra_iovmm_alloc_client(const char *name,
const char *share_group, struct miscdevice *misc_dev);
+static inline struct tegra_iovmm_client *tegra_iovmm_alloc_client(
+ struct device *dev, const char *share_group,
+ struct miscdevice *misc_dev)
+{
+ return __tegra_iovmm_alloc_client(dev_name(dev), share_group, misc_dev);
+}
+
size_t tegra_iovmm_get_vm_size(struct tegra_iovmm_client *client);
void tegra_iovmm_free_client(struct tegra_iovmm_client *client);
@@ -220,7 +248,8 @@ int tegra_iovmm_unregister(struct tegra_iovmm_device *dev);
#else /* CONFIG_TEGRA_IOVMM */
static inline struct tegra_iovmm_client *tegra_iovmm_alloc_client(
- const char *name, const char *share_group, struct miscdevice *misc_dev)
+ struct device *dev, const char *share_group,
+ struct miscdevice *misc_dev)
{
return NULL;
}
@@ -319,5 +348,37 @@ static inline void tegra_iovmm_resume(void)
{
}
+#ifdef CONFIG_IOMMU_API
+/*
+ * Replace tegra_iovmm_*() with tegra_iommu_*() helpers
+ */
+#include <linux/dma-mapping.h>
+#include <linux/dma-direction.h>
+
+#include <asm/dma-iommu.h>
+
+#define tegra_iovmm_alloc_client(d, s, m) tegra_iommu_alloc_client(d)
+#define tegra_iovmm_free_client(c) tegra_iommu_free_client(c)
+
+#define tegra_iovmm_create_vm(c, o, s, a, p, i) \
+ tegra_iommu_create_vm((c)->dev, i, s, p)
+#define tegra_iovmm_free_vm(v) tegra_iommu_free_vm(v)
+
+#define tegra_iovmm_get_vm_size(c) arm_iommu_iova_avail((c)->dev)
+#define tegra_iovmm_get_max_free(c) arm_iommu_iova_max_free((c)->dev)
+
+#define tegra_iovmm_vm_insert_pfn(a, v, n) \
+ dma_map_page_at((a)->dev, pfn_to_page(n), v, 0, PAGE_SIZE, DMA_NONE);
+
+struct tegra_iovmm_area *tegra_iommu_create_vm(struct device *dev,
+ dma_addr_t req, size_t size, pgprot_t prot);
+
+void tegra_iommu_free_vm(struct tegra_iovmm_area *area);
+
+struct tegra_iovmm_client *tegra_iommu_alloc_client(struct device *dev);
+
+void tegra_iommu_free_client(struct tegra_iovmm_client *client);
+
+#endif /* CONFIG_IOMMU_API */
#endif /* CONFIG_TEGRA_IOVMM */
#endif /* _MACH_TEGRA_IOVMM_H_*/
diff --git a/arch/arm/mach-tegra/include/mach/latency_allowance.h b/arch/arm/mach-tegra/include/mach/latency_allowance.h
index f0d27f0b8ba9..8644075a88b3 100644
--- a/arch/arm/mach-tegra/include/mach/latency_allowance.h
+++ b/arch/arm/mach-tegra/include/mach/latency_allowance.h
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/include/mach/latency_allowance.h
*
- * Copyright (C) 2011, NVIDIA Corporation.
+ * Copyright (C) 2011-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
@@ -104,7 +104,7 @@ static inline int tegra_enable_latency_scaling(enum tegra_la_id id,
static inline void tegra_disable_latency_scaling(enum tegra_la_id id)
{
- return 0;
+ return;
}
#else
int tegra_set_latency_allowance(enum tegra_la_id id,
diff --git a/arch/arm/mach-tegra/include/mach/legacy_irq.h b/arch/arm/mach-tegra/include/mach/legacy_irq.h
index 86f1ff7d06b0..3cd2d82c342f 100644
--- a/arch/arm/mach-tegra/include/mach/legacy_irq.h
+++ b/arch/arm/mach-tegra/include/mach/legacy_irq.h
@@ -19,5 +19,7 @@
#define _ARCH_ARM_MACH_TEGRA_LEGARY_IRQ_H
void tegra_init_legacy_irq_cop(void);
+/* lp1 wake interrupts enabled or disabled using this API */
+int tegra_update_lp1_irq_wake(unsigned int irq, bool enable);
#endif
diff --git a/arch/arm/mach-tegra/include/mach/sdhci.h b/arch/arm/mach-tegra/include/mach/sdhci.h
index b48a92887070..e307506eb40b 100644
--- a/arch/arm/mach-tegra/include/mach/sdhci.h
+++ b/arch/arm/mach-tegra/include/mach/sdhci.h
@@ -20,6 +20,14 @@
#include <linux/mmc/host.h>
#include <asm/mach/mmc.h>
+/*
+ * MMC_OCR_1V8_MASK will be used in board sdhci file
+ * Example for cardhu it will be used in board-cardhu-sdhci.c
+ * for built_in = 0 devices enabling ocr_mask to MMC_OCR_1V8_MASK
+ * sets the voltage to 1.8V
+ */
+#define MMC_OCR_1V8_MASK 0x8
+
struct tegra_sdhci_platform_data {
int cd_gpio;
int wp_gpio;
@@ -28,6 +36,7 @@ struct tegra_sdhci_platform_data {
int pm_flags;
int pm_caps;
unsigned int max_clk_limit;
+ unsigned int ddr_clk_limit;
unsigned int tap_delay;
struct mmc_platform_data mmc_data;
};
diff --git a/arch/arm/mach-tegra/include/mach/tegra_p1852_pdata.h b/arch/arm/mach-tegra/include/mach/tegra_p1852_pdata.h
index bfd61c460051..501d815b881b 100644
--- a/arch/arm/mach-tegra/include/mach/tegra_p1852_pdata.h
+++ b/arch/arm/mach-tegra/include/mach/tegra_p1852_pdata.h
@@ -35,8 +35,15 @@ struct codec_info_s {
char *cpu_dai_name;
char *codec_name; /* Name of the Codec Driver */
char *name; /* Name of the Codec-Dai-Link */
+ char *pcm_driver; /* Name of the PCM driver */
enum i2s_data_format i2s_format;
int master; /* Codec is Master or Slave */
+ /* TDM format setttings */
+ int num_slots; /* Number of TDM slots */
+ int slot_width; /* Width of each slot */
+ int rx_mask; /* Number of Rx Enabled slots */
+ int tx_mask; /* Number of Tx Enabled slots */
+
};
struct tegra_p1852_platform_data {
diff --git a/arch/arm/mach-tegra/include/mach/tegra_usb_modem_power.h b/arch/arm/mach-tegra/include/mach/tegra_usb_modem_power.h
index 0ce7fa40eb2e..210b9f61ecb5 100644
--- a/arch/arm/mach-tegra/include/mach/tegra_usb_modem_power.h
+++ b/arch/arm/mach-tegra/include/mach/tegra_usb_modem_power.h
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/include/mach/tegra_usb_modem_power.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
@@ -40,8 +40,14 @@ struct tegra_modem_operations {
/* tegra usb modem power platform data */
struct tegra_usb_modem_power_platform_data {
const struct tegra_modem_operations *ops;
- unsigned int wake_gpio; /* remote wakeup gpio */
- unsigned int flags; /* remote wakeup irq flags */
+ unsigned int wake_gpio; /* remote wakeup gpio */
+ unsigned long wake_irq_flags; /* remote wakeup irq flags */
+ unsigned int boot_gpio; /* modem boot gpio */
+ unsigned long boot_irq_flags; /* modem boot irq flags */
+ int autosuspend_delay; /* autosuspend delay in milliseconds */
+ int short_autosuspend_delay; /* short autosuspend delay in ms */
+ const struct platform_device *tegra_ehci_device;
+ const struct tegra_usb_platform_data *tegra_ehci_pdata;
};
#endif /* __MACH_TEGRA_USB_MODEM_POWER_H */
diff --git a/arch/arm/mach-tegra/include/mach/thermal.h b/arch/arm/mach-tegra/include/mach/thermal.h
index ab7b34492d9e..ed71d0340a96 100644
--- a/arch/arm/mach-tegra/include/mach/thermal.h
+++ b/arch/arm/mach-tegra/include/mach/thermal.h
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/thermal.h
*
- * Copyright (C) 2010-2011 NVIDIA Corporation.
+ * 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
@@ -17,26 +17,62 @@
#ifndef __MACH_THERMAL_H
#define __MACH_THERMAL_H
+#include <linux/therm_est.h>
+
+enum thermal_device_id {
+ THERMAL_DEVICE_ID_NULL = 0x0,
+ THERMAL_DEVICE_ID_NCT_EXT = 0x1,
+ THERMAL_DEVICE_ID_NCT_INT = 0x2,
+ THERMAL_DEVICE_ID_TSENSOR = 0x4,
+ THERMAL_DEVICE_ID_SKIN = 0x8,
+};
+
+#define THERMAL_DEVICE_MAX (4)
+
+enum balanced_throttle_id {
+ BALANCED_THROTTLE_ID_TJ,
+ BALANCED_THROTTLE_ID_SKIN,
+};
+
+struct skin_therm_est_subdevice {
+ enum thermal_device_id id;
+ long coeffs[HIST_LEN];
+};
+
/* All units in millicelsius */
struct tegra_thermal_data {
- long temp_throttle;
+ enum thermal_device_id shutdown_device_id;
long temp_shutdown;
- long temp_offset;
+#if defined(CONFIG_TEGRA_EDP_LIMITS) || defined(CONFIG_TEGRA_THERMAL_THROTTLE)
+ enum thermal_device_id throttle_edp_device_id;
+#endif
#ifdef CONFIG_TEGRA_EDP_LIMITS
long edp_offset;
long hysteresis_edp;
#endif
-#ifdef CONFIG_TEGRA_THERMAL_SYSFS
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
+ long temp_throttle;
int tc1;
int tc2;
long passive_delay;
-#else
- long hysteresis_throttle;
+#endif
+#ifdef CONFIG_TEGRA_SKIN_THROTTLE
+ enum thermal_device_id skin_device_id;
+ long temp_throttle_skin;
+ int tc1_skin;
+ int tc2_skin;
+ int passive_delay_skin;
+
+ long skin_temp_offset;
+ long skin_period;
+ int skin_devs_size;
+ struct skin_therm_est_subdevice skin_devs[];
#endif
};
struct tegra_thermal_device {
char *name;
+ enum thermal_device_id id;
void *data;
long offset;
int (*get_temp) (void *, long *);
@@ -44,16 +80,51 @@ struct tegra_thermal_device {
int (*set_limits) (void *, long, long);
int (*set_alert)(void *, void (*)(void *), void *);
int (*set_shutdown_temp)(void *, long);
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
+ struct thermal_zone_device *thz;
+#endif
+ struct list_head node;
+};
+
+struct throttle_table {
+ unsigned int cpu_freq;
+ int core_cap_level;
};
+#define MAX_THROT_TABLE_SIZE (32)
+
+struct balanced_throttle {
+ enum balanced_throttle_id id;
+
+ int is_throttling;
+ int throttle_index;
+ struct thermal_cooling_device *cdev;
+
+ struct list_head node;
+
+ int throt_tab_size;
+ struct throttle_table throt_tab[MAX_THROT_TABLE_SIZE];
+};
+
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
+int balanced_throttle_register(struct balanced_throttle *bthrot);
+#else
+static inline int balanced_throttle_register(struct balanced_throttle *bthrot)
+{ return 0; }
+#endif
+
#ifndef CONFIG_ARCH_TEGRA_2x_SOC
-int tegra_thermal_init(struct tegra_thermal_data *data);
-int tegra_thermal_set_device(struct tegra_thermal_device *device);
+int tegra_thermal_init(struct tegra_thermal_data *data,
+ struct balanced_throttle *throttle_list,
+ int throttle_list_size);
+int tegra_thermal_device_register(struct tegra_thermal_device *device);
int tegra_thermal_exit(void);
#else
-static inline int tegra_thermal_init(struct tegra_thermal_data *data)
+static inline int tegra_thermal_init(struct tegra_thermal_data *data,
+ struct balanced_throttle throttle_list,
+ int throttle_list_size);
{ return 0; }
-static inline int tegra_thermal_set_device(struct tegra_thermal_device *dev)
+static int tegra_thermal_device_register(struct tegra_thermal_device *device)
{ return 0; }
static inline int tegra_thermal_exit(void)
{ return 0; }
diff --git a/arch/arm/mach-tegra/include/mach/usb_phy.h b/arch/arm/mach-tegra/include/mach/usb_phy.h
index 46fe8c84a2f3..c721642c4417 100644
--- a/arch/arm/mach-tegra/include/mach/usb_phy.h
+++ b/arch/arm/mach-tegra/include/mach/usb_phy.h
@@ -18,151 +18,120 @@
#ifndef __MACH_USB_PHY_H
#define __MACH_USB_PHY_H
-#include <linux/clk.h>
-#include <linux/regulator/consumer.h>
-#include <linux/usb/otg.h>
-#include <linux/platform_data/tegra_usb.h>
-
-struct tegra_utmip_config {
- u8 hssync_start_delay;
- u8 elastic_limit;
- u8 idle_wait_delay;
- u8 term_range_adj;
- u8 xcvr_setup;
- signed char xcvr_setup_offset;
- u8 xcvr_use_fuses;
- u8 xcvr_lsfslew;
- u8 xcvr_lsrslew;
-};
-
-struct tegra_ulpi_trimmer {
- u8 shadow_clk_delay; /* 0 ~ 31 */
- u8 clock_out_delay; /* 0 ~ 31 */
- u8 data_trimmer; /* 0 ~ 7 */
- u8 stpdirnxt_trimmer; /* 0 ~ 7 */
-};
-
-struct tegra_ulpi_config {
- int enable_gpio;
- int reset_gpio;
- const char *clk;
- const struct tegra_ulpi_trimmer *trimmer;
- int (*pre_phy_on)(void);
- int (*post_phy_on)(void);
- int (*pre_phy_off)(void);
- int (*post_phy_off)(void);
- void (*phy_restore_start)(void);
- void (*phy_restore_end)(void);
- int phy_restore_gpio; /* null phy restore ack from device */
- int ulpi_dir_gpio; /* ulpi dir */
- int ulpi_d0_gpio; /* usb linestate[0] */
- int ulpi_d1_gpio; /* usb linestate[1] */
-};
-
-struct tegra_uhsic_config {
- int enable_gpio;
- int reset_gpio;
- u8 sync_start_delay;
- u8 idle_wait_delay;
- u8 term_range_adj;
- u8 elastic_underrun_limit;
- u8 elastic_overrun_limit;
- int (*postsuspend)(void);
- int (*preresume)(void);
- int (*usb_phy_ready)(void);
- int (*post_phy_off)(void);
-};
-
-enum tegra_usb_phy_port_speed {
- TEGRA_USB_PHY_PORT_SPEED_FULL = 0,
- TEGRA_USB_PHY_PORT_SPEED_LOW,
- TEGRA_USB_PHY_PORT_SPEED_HIGH,
-};
-
-enum tegra_usb_phy_mode {
- TEGRA_USB_PHY_MODE_DEVICE,
- TEGRA_USB_PHY_MODE_HOST,
-};
-
-struct usb_phy_plat_data {
- int instance;
- int vbus_irq;
- int vbus_gpio;
- int vbus_gpio_inverted;
- char * vbus_reg_supply;
-};
-
-struct tegra_xtal_freq;
-
-struct tegra_usb_phy {
- int instance;
- const struct tegra_xtal_freq *freq;
- void __iomem *regs;
- void __iomem *pad_regs;
- struct clk *clk;
- struct clk *pll_u;
- struct clk *pad_clk;
- enum tegra_usb_phy_mode mode;
- void *config;
- struct regulator *reg_vdd;
- struct regulator *reg_vbus;
- enum tegra_usb_phy_type usb_phy_type;
- bool regulator_on;
- struct otg_transceiver *ulpi;
- int initialized;
- bool power_on;
- bool remote_wakeup;
- int hotplug;
- unsigned int xcvr_setup_value;
-};
-
-typedef int (*tegra_phy_fp)(struct tegra_usb_phy *phy, bool is_dpd);
-typedef void (*tegra_phy_restore_start_fp)(struct tegra_usb_phy *phy,
- enum tegra_usb_phy_port_speed);
-typedef void (*tegra_phy_restore_end_fp)(struct tegra_usb_phy *phy);
-
-struct tegra_usb_phy *tegra_usb_phy_open(int instance, void __iomem *regs,
- void *config, enum tegra_usb_phy_mode phy_mode,
- enum tegra_usb_phy_type usb_phy_type);
-
-int tegra_usb_phy_power_on(struct tegra_usb_phy *phy, bool is_dpd);
-
-void tegra_usb_phy_clk_disable(struct tegra_usb_phy *phy);
-
-void tegra_usb_phy_clk_enable(struct tegra_usb_phy *phy);
-
-void tegra_usb_phy_power_off(struct tegra_usb_phy *phy, bool is_dpd);
-
-void tegra_usb_phy_postsuspend(struct tegra_usb_phy *phy, bool is_dpd);
-
-void tegra_usb_phy_preresume(struct tegra_usb_phy *phy, bool is_dpd);
-
-void tegra_usb_phy_postresume(struct tegra_usb_phy *phy, bool is_dpd);
-
-void tegra_ehci_pre_reset(struct tegra_usb_phy *phy, bool is_dpd);
-
-void tegra_ehci_post_reset(struct tegra_usb_phy *phy, bool is_dpd);
-
-void tegra_ehci_phy_restore_start(struct tegra_usb_phy *phy,
- enum tegra_usb_phy_port_speed port_speed);
-
-void tegra_ehci_phy_restore_end(struct tegra_usb_phy *phy);
+/**
+ * Tegra USB phy opaque handle
+ */
+struct tegra_usb_phy;
+
+/**
+ * Opens the usb phy associated to the USB platform device
+ * tegra usb phy open must be called before accessing any phy APIs
+ */
+struct tegra_usb_phy *tegra_usb_phy_open(struct platform_device *pdev);
+/**
+ * Closes the phy controller and its resources
+ */
void tegra_usb_phy_close(struct tegra_usb_phy *phy);
-int tegra_usb_phy_bus_connect(struct tegra_usb_phy *phy);
+/**
+ * Handles interrupts specific to the phy interface
+ * Note: udc or ehci driver will handle the controller interrupts
+ */
+int tegra_usb_phy_irq(struct tegra_usb_phy *phy);
+
+/**
+ * Initializes the phy specific functions after phy is power on
+ */
+int tegra_usb_phy_init(struct tegra_usb_phy *phy);
+
+/**
+ * Handles phy interface specific functionality after driver reset
+ */
+int tegra_usb_phy_reset(struct tegra_usb_phy *phy);
+
+/**
+ * Handles phy interface specific functionality before driver suspend
+ * Also, handles platform specific pre suspend functions
+ */
+int tegra_usb_phy_pre_suspend(struct tegra_usb_phy *phy);
+
+/**
+ * Handles phy interface specific suspend functionality
+ */
+int tegra_usb_phy_suspend(struct tegra_usb_phy *phy);
+
+/**
+ * Handles phy interface specific functionality after driver suspend
+ */
+int tegra_usb_phy_post_suspend(struct tegra_usb_phy *phy);
+
+/**
+ * Handles phy interface specific functionality before driver resume
+ * Also, handles platform specific pre resume functions
+ */
+int tegra_usb_phy_pre_resume(struct tegra_usb_phy *phy, bool remote_wakeup);
+
+/**
+ * Handles phy interface specific resume functionality
+ */
+int tegra_usb_phy_resume(struct tegra_usb_phy *phy);
+/**
+ * Handles phy interface specific functionality after driver resume
+ */
+int tegra_usb_phy_post_resume(struct tegra_usb_phy *phy);
+
+/**
+ * Handles phy interface specific functionality during port power on
+ */
+int tegra_usb_phy_port_power(struct tegra_usb_phy *phy);
+
+/**
+ * Handles phy interface specific functionality during bus reset
+ */
int tegra_usb_phy_bus_reset(struct tegra_usb_phy *phy);
-int tegra_usb_phy_bus_idle(struct tegra_usb_phy *phy);
+/**
+ * Handles phy interface specific functionality for turning off the phy to
+ * put the phy in low power mode
+ */
+int tegra_usb_phy_power_off(struct tegra_usb_phy *phy);
-bool tegra_usb_phy_is_device_connected(struct tegra_usb_phy *phy);
+/**
+ * Handles phy interface specific functionality for turning on the phy to
+ * bring phy out of low power mode
+ */
+int tegra_usb_phy_power_on(struct tegra_usb_phy *phy);
-bool tegra_usb_phy_charger_detect(struct tegra_usb_phy *phy);
+/**
+ * Indicates whether phy registers are accessible or not
+ * if phy is powered off then returns false else true
+ */
+bool tegra_usb_phy_hw_accessible(struct tegra_usb_phy *phy);
+
+/**
+ * Indicates whether compliance charger is connected or not
+ * if compliance charger is detected then returns true else false
+ */
+bool tegra_usb_phy_charger_detected(struct tegra_usb_phy *phy);
+
+/**
+ * Indicates whether phy resumed due to the remote wake event or not
+ * returns true if remote wake is detected.
+ */
+bool tegra_usb_phy_remote_wakeup(struct tegra_usb_phy *phy);
+
+/**
+ * Indicates controller has HOST PC register set or not
+ */
+bool tegra_usb_phy_has_hostpc(struct tegra_usb_phy *phy);
-int __init tegra_usb_phy_init(struct usb_phy_plat_data *pdata, int size);
+/**
+ * Indicates controller port supports OTG or not
+ */
+bool tegra_usb_phy_otg_supported(struct tegra_usb_phy *phy);
-bool tegra_usb_phy_is_remotewake_detected(struct tegra_usb_phy *phy);
void tegra_usb_phy_memory_prefetch_on(struct tegra_usb_phy *phy);
diff --git a/arch/arm/mach-tegra/iovmm-gart.c b/arch/arm/mach-tegra/iovmm-gart.c
index ad1ce3a7afc3..130901cb4883 100644
--- a/arch/arm/mach-tegra/iovmm-gart.c
+++ b/arch/arm/mach-tegra/iovmm-gart.c
@@ -4,7 +4,7 @@
* Tegra I/O VMM implementation for GART devices in Tegra and Tegra 2 series
* systems-on-a-chip.
*
- * Copyright (c) 2010-2012, 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
@@ -73,7 +73,7 @@ static int gart_map(struct tegra_iovmm_domain *, struct tegra_iovmm_area *);
static void gart_unmap(struct tegra_iovmm_domain *,
struct tegra_iovmm_area *, bool);
static void gart_map_pfn(struct tegra_iovmm_domain *,
- struct tegra_iovmm_area *, tegra_iovmm_addr_t, unsigned long);
+ struct tegra_iovmm_area *, unsigned long, unsigned long);
static struct tegra_iovmm_domain *gart_alloc_domain(
struct tegra_iovmm_device *, struct tegra_iovmm_client *);
@@ -330,7 +330,7 @@ static void gart_unmap(struct tegra_iovmm_domain *domain,
}
static void gart_map_pfn(struct tegra_iovmm_domain *domain,
- struct tegra_iovmm_area *iovma, tegra_iovmm_addr_t offs,
+ struct tegra_iovmm_area *iovma, unsigned long offs,
unsigned long pfn)
{
struct gart_device *gart =
diff --git a/arch/arm/mach-tegra/iovmm-smmu.c b/arch/arm/mach-tegra/iovmm-smmu.c
index 31c7d4884181..6cdeb744a04c 100644
--- a/arch/arm/mach-tegra/iovmm-smmu.c
+++ b/arch/arm/mach-tegra/iovmm-smmu.c
@@ -310,10 +310,14 @@ struct smmu_device {
/*
* Register image savers for suspend/resume
*/
- unsigned long translation_enable_0_0;
- unsigned long translation_enable_1_0;
- unsigned long translation_enable_2_0;
- unsigned long asid_security_0;
+ unsigned long config_0; /* Secure reg */
+ unsigned long tlb_config_0;
+ unsigned long ptc_config_0;
+ unsigned long ptb_asid_0;
+ unsigned long translation_enable_0_0; /* Secure reg */
+ unsigned long translation_enable_1_0; /* Secure reg */
+ unsigned long translation_enable_2_0; /* Secure reg */
+ unsigned long asid_security_0; /* Secure reg */
unsigned long lowest_asid; /* Variables for hardware testing */
unsigned long debug_asid;
@@ -335,13 +339,13 @@ struct smmu_device {
* must have these read-back to ensure the APB/AHB bus transaction is
* complete before initiating activity on the PPSB block.
*/
-#define FLUSH_SMMU_REGS(smmu) (void)readl((smmu)->regs + MC_SMMU_CONFIG_0)
+#define FLUSH_SMMU_REGS(smmu) (void)readl((smmu)->regs + MC_SMMU_PTB_DATA_0)
/*
* Flush all TLB entries and all PTC entries
* Caller must lock smmu
*/
-static void smmu_flush_regs(struct smmu_device *smmu, int enable)
+static void smmu_flush_regs(struct smmu_device *smmu)
{
writel(MC_SMMU_PTC_FLUSH_0_PTC_FLUSH_TYPE_ALL,
smmu->regs + MC_SMMU_PTC_FLUSH_0);
@@ -349,10 +353,6 @@ static void smmu_flush_regs(struct smmu_device *smmu, int enable)
writel(MC_SMMU_TLB_FLUSH_0_TLB_FLUSH_VA_MATCH_ALL |
MC_SMMU_TLB_FLUSH_0_TLB_FLUSH_ASID_MATCH_disable,
smmu->regs + MC_SMMU_TLB_FLUSH_0);
-
- if (enable)
- writel(MC_SMMU_CONFIG_0_SMMU_ENABLE_ENABLE,
- smmu->regs + MC_SMMU_CONFIG_0);
FLUSH_SMMU_REGS(smmu);
}
@@ -388,14 +388,14 @@ static void smmu_setup_regs(struct smmu_device *smmu)
smmu->regs + MC_SMMU_TRANSLATION_ENABLE_1_0);
writel(smmu->translation_enable_2_0,
smmu->regs + MC_SMMU_TRANSLATION_ENABLE_2_0);
- writel(smmu->asid_security_0,
- smmu->regs + MC_SMMU_ASID_SECURITY_0);
- writel(MC_SMMU_TLB_CONFIG_0_RESET_VAL,
- smmu->regs + MC_SMMU_TLB_CONFIG_0);
- writel(MC_SMMU_PTC_CONFIG_0_RESET_VAL,
- smmu->regs + MC_SMMU_PTC_CONFIG_0);
-
- smmu_flush_regs(smmu, 1);
+ writel(smmu->asid_security_0, smmu->regs + MC_SMMU_ASID_SECURITY_0);
+ writel(smmu->ptb_asid_0, smmu->regs + MC_SMMU_PTB_ASID_0);
+ writel(smmu->ptc_config_0, smmu->regs + MC_SMMU_PTC_CONFIG_0);
+ writel(smmu->tlb_config_0, smmu->regs + MC_SMMU_TLB_CONFIG_0);
+ writel(smmu->config_0, smmu->regs + MC_SMMU_CONFIG_0);
+
+ smmu_flush_regs(smmu);
+
writel(
readl(smmu->regs_ahbarb + AHB_ARBITRATION_XBAR_CTRL_0) |
(AHB_ARBITRATION_XBAR_CTRL_0_SMMU_INIT_DONE_DONE <<
@@ -408,6 +408,10 @@ static int smmu_suspend(struct tegra_iovmm_device *dev)
struct smmu_device *smmu =
container_of(dev, struct smmu_device, iovmm_dev);
+ smmu->config_0 = readl(smmu->regs + MC_SMMU_CONFIG_0);
+ smmu->tlb_config_0 = readl(smmu->regs + MC_SMMU_TLB_CONFIG_0);
+ smmu->ptc_config_0 = readl(smmu->regs + MC_SMMU_PTC_CONFIG_0);
+ smmu->ptb_asid_0 = readl(smmu->regs + MC_SMMU_PTB_ASID_0);
smmu->translation_enable_0_0 =
readl(smmu->regs + MC_SMMU_TRANSLATION_ENABLE_0_0);
smmu->translation_enable_1_0 =
@@ -691,10 +695,8 @@ static void smmu_unmap(struct tegra_iovmm_domain *domain,
flush_ptc_and_tlb(as->smmu, as, addr, pte,
page, 0);
kunmap(page);
- if (!--(*pte_counter) && decommit) {
+ if (!--(*pte_counter) && decommit)
free_ptbl(as, addr);
- smmu_flush_regs(as->smmu, 0);
- }
}
}
addr += SMMU_PAGE_SIZE;
@@ -966,10 +968,14 @@ static int smmu_probe(struct platform_device *pdev)
goto fail;
}
+ smmu->config_0 = MC_SMMU_CONFIG_0_SMMU_ENABLE_ENABLE;
+ smmu->tlb_config_0 = MC_SMMU_TLB_CONFIG_0_RESET_VAL;
+ smmu->ptc_config_0 = MC_SMMU_PTC_CONFIG_0_RESET_VAL;
+ smmu->ptb_asid_0 = 0;
smmu->translation_enable_0_0 = ~0;
smmu->translation_enable_1_0 = ~0;
smmu->translation_enable_2_0 = ~0;
- smmu->asid_security_0 = 0;
+ smmu->asid_security_0 = 0;
memcpy(smmu->hwc_state, smmu_hwc_state_init, sizeof(smmu->hwc_state));
diff --git a/arch/arm/mach-tegra/iovmm.c b/arch/arm/mach-tegra/iovmm.c
index 6112128cb743..86a92aec2d28 100644
--- a/arch/arm/mach-tegra/iovmm.c
+++ b/arch/arm/mach-tegra/iovmm.c
@@ -805,7 +805,7 @@ void tegra_iovmm_free_client(struct tegra_iovmm_client *client)
mutex_unlock(&iovmm_group_list_lock);
}
-struct tegra_iovmm_client *tegra_iovmm_alloc_client(const char *name,
+struct tegra_iovmm_client *__tegra_iovmm_alloc_client(const char *name,
const char *share_group, struct miscdevice *misc_dev)
{
struct tegra_iovmm_client *c = kzalloc(sizeof(*c), GFP_KERNEL);
diff --git a/arch/arm/mach-tegra/irq.c b/arch/arm/mach-tegra/irq.c
index 450295d901dd..278912486f40 100644
--- a/arch/arm/mach-tegra/irq.c
+++ b/arch/arm/mach-tegra/irq.c
@@ -26,6 +26,7 @@
#include <asm/hardware/gic.h>
#include <mach/iomap.h>
+#include <mach/gpio.h>
#include <mach/legacy_irq.h>
#include "board.h"
@@ -66,10 +67,34 @@ static void __iomem *ictlr_reg_base[] = {
#ifdef CONFIG_PM_SLEEP
static u32 cop_ier[NUM_ICTLRS];
+static u32 cop_iep[NUM_ICTLRS];
static u32 cpu_ier[NUM_ICTLRS];
static u32 cpu_iep[NUM_ICTLRS];
+
+static u32 ictlr_wake_mask[NUM_ICTLRS];
+#endif
+
+int tegra_update_lp1_irq_wake(unsigned int irq, bool enable)
+{
+#ifdef CONFIG_PM_SLEEP
+ u8 index;
+ u32 mask;
+
+ if (irq < FIRST_LEGACY_IRQ ||
+ irq >= FIRST_LEGACY_IRQ + NUM_ICTLRS * 32)
+ return -EINVAL;
+
+ index = ((irq - FIRST_LEGACY_IRQ) >> 5);
+ mask = BIT((irq - FIRST_LEGACY_IRQ) % 32);
+ if (enable)
+ ictlr_wake_mask[index] |= mask;
+ else
+ ictlr_wake_mask[index] &= ~mask;
#endif
+ return 0;
+}
+
static inline void tegra_irq_write_mask(unsigned int irq, unsigned long reg)
{
void __iomem *base;
@@ -131,11 +156,28 @@ static int tegra_set_type(struct irq_data *d, unsigned int flow_type)
return tegra_pm_irq_set_wake_type(d->irq, flow_type);
}
-
#ifdef CONFIG_PM_SLEEP
+/*
+ * Caller ensures that tegra_set_wake (irq_set_wake callback)
+ * is called for non-gpio wake sources only
+ */
static int tegra_set_wake(struct irq_data *d, unsigned int enable)
{
- return tegra_pm_irq_set_wake(d->irq, enable);
+ int ret;
+
+ /* pmc lp0 wake enable for non-gpio wake sources */
+ ret = tegra_pm_irq_set_wake(d->irq, enable);
+ if (ret)
+ pr_err("Failed lp0 wake %s for irq=%d\n",
+ (enable ? "enable" : "disable"), d->irq);
+
+ /* lp1 wake enable for wake sources */
+ ret = tegra_update_lp1_irq_wake(d->irq, enable);
+ if (ret)
+ pr_err("Failed lp1 wake %s for irq=%d\n",
+ (enable ? "enable" : "disable"), d->irq);
+
+ return ret;
}
static int tegra_legacy_irq_suspend(void)
@@ -146,9 +188,13 @@ static int tegra_legacy_irq_suspend(void)
local_irq_save(flags);
for (i = 0; i < NUM_ICTLRS; i++) {
void __iomem *ictlr = ictlr_reg_base[i];
+ /* save interrupt state */
cpu_ier[i] = readl(ictlr + ICTLR_CPU_IER);
cpu_iep[i] = readl(ictlr + ICTLR_CPU_IEP_CLASS);
cop_ier[i] = readl(ictlr + ICTLR_COP_IER);
+ cop_iep[i] = readl(ictlr + ICTLR_COP_IEP_CLASS);
+
+ /* disable COP interrupts */
writel(~0, ictlr + ICTLR_COP_IER_CLR);
}
local_irq_restore(flags);
@@ -167,7 +213,7 @@ static void tegra_legacy_irq_resume(void)
writel(cpu_iep[i], ictlr + ICTLR_CPU_IEP_CLASS);
writel(~0ul, ictlr + ICTLR_CPU_IER_CLR);
writel(cpu_ier[i], ictlr + ICTLR_CPU_IER_SET);
- writel(0, ictlr + ICTLR_COP_IEP_CLASS);
+ writel(cop_iep[i], ictlr + ICTLR_COP_IEP_CLASS);
writel(~0ul, ictlr + ICTLR_COP_IER_CLR);
writel(cop_ier[i], ictlr + ICTLR_COP_IER_SET);
}
diff --git a/arch/arm/mach-tegra/p852/board-p852-panel.c b/arch/arm/mach-tegra/p852/board-p852-panel.c
index c47032dd4f0a..8ed62f039dc8 100644
--- a/arch/arm/mach-tegra/p852/board-p852-panel.c
+++ b/arch/arm/mach-tegra/p852/board-p852-panel.c
@@ -25,13 +25,14 @@
#include <linux/nvhost.h>
#include <linux/platform_device.h>
#include <asm/mach-types.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include <mach/irqs.h>
#include <mach/iomap.h>
#include <mach/dc.h>
#include <mach/fb.h>
#include "board-p852.h"
+#include "../tegra2_host1x_devices.h"
#define CARVEOUT_IRAM {\
.name = "iram",\
@@ -175,7 +176,7 @@ int __init p852_panel_init(void)
return err;
#ifdef CONFIG_TEGRA_GRHOST
- err = nvhost_device_register(&tegra_grhost_device);
+ err = tegra2_register_host1x_devices();
if (err)
return err;
#endif
diff --git a/arch/arm/mach-tegra/p852/board-p852.c b/arch/arm/mach-tegra/p852/board-p852.c
index 21b867e15177..039d9db6a3a6 100644
--- a/arch/arm/mach-tegra/p852/board-p852.c
+++ b/arch/arm/mach-tegra/p852/board-p852.c
@@ -288,49 +288,6 @@ static struct platform_device debug_uart = {
},
};
-static struct tegra_utmip_config utmi_phy_config[] = {
- [0] = {
- .hssync_start_delay = 0,
- .idle_wait_delay = 17,
- .elastic_limit = 16,
- .term_range_adj = 6,
- .xcvr_setup = 15,
- .xcvr_lsfslew = 2,
- .xcvr_lsrslew = 2,
- },
- [1] = {
- .hssync_start_delay = 0,
- .idle_wait_delay = 17,
- .elastic_limit = 16,
- .term_range_adj = 6,
- .xcvr_setup = 8,
- .xcvr_lsfslew = 2,
- .xcvr_lsrslew = 2,
- },
-};
-
-static struct tegra_ulpi_config ulpi_usb2_config = {
- .reset_gpio = TEGRA_GPIO_PI5,
-};
-
-static struct tegra_ehci_platform_data tegra_ehci_pdata[] = {
- [0] = {
- .phy_config = &utmi_phy_config[0],
- .operating_mode = TEGRA_USB_HOST,
- .power_down_on_bus_suspend = 0,
- },
- [1] = {
- .phy_config = &ulpi_usb2_config,
- .operating_mode = TEGRA_USB_HOST,
- .power_down_on_bus_suspend = 0,
- .phy_type = TEGRA_USB_PHY_TYPE_LINK_ULPI,
- },
- [2] = {
- .phy_config = &utmi_phy_config[1],
- .operating_mode = TEGRA_USB_HOST,
- .power_down_on_bus_suspend = 0,
- },
-};
static void p852_usb_gpio_config(void)
{
@@ -529,6 +486,97 @@ static void __init p852_register_spidev(void)
#define p852_register_spidev() do {} while (0)
#endif
+/*
+ FixMe: Copied below GPIO value from Ventana board.
+ Plz correct it accordingly for embedded board usage
+*/
+#define TEGRA_GPIO_PV1 169
+
+static void ulpi_link_platform_open(void)
+{
+ int reset_gpio = TEGRA_GPIO_PV1;
+
+ gpio_request(reset_gpio, "ulpi_phy_reset");
+ gpio_direction_output(reset_gpio, 0);
+ tegra_gpio_enable(reset_gpio);
+
+ gpio_direction_output(reset_gpio, 0);
+ msleep(5);
+ gpio_direction_output(reset_gpio, 1);
+}
+
+static struct tegra_usb_phy_platform_ops ulpi_link_plat_ops = {
+ .open = ulpi_link_platform_open,
+};
+
+static struct tegra_usb_platform_data tegra_ehci_ulpi_link_pdata = {
+ .port_otg = false,
+ .has_hostpc = false,
+ .phy_intf = TEGRA_USB_PHY_INTF_ULPI_LINK,
+ .op_mode = TEGRA_USB_OPMODE_HOST,
+ .u_data.host = {
+ .vbus_gpio = -1,
+ .vbus_reg = NULL,
+ .hot_plug = false,
+ .remote_wakeup_supported = false,
+ .power_off_on_suspend = false,
+ },
+ .u_cfg.ulpi = {
+ .shadow_clk_delay = 10,
+ .clock_out_delay = 1,
+ .data_trimmer = 4,
+ .stpdirnxt_trimmer = 4,
+ .dir_trimmer = 4,
+ .clk = "cdev2",
+ },
+ .ops = &ulpi_link_plat_ops,
+};
+
+static struct tegra_usb_platform_data tegra_ehci1_utmi_pdata = {
+ .port_otg = false,
+ .has_hostpc = false,
+ .phy_intf = TEGRA_USB_PHY_INTF_UTMI,
+ .op_mode = TEGRA_USB_OPMODE_HOST,
+ .u_data.host = {
+ .vbus_gpio = -1,
+ .vbus_reg = NULL,
+ .hot_plug = true,
+ .remote_wakeup_supported = true,
+ .power_off_on_suspend = false,
+ },
+ .u_cfg.utmi = {
+ .hssync_start_delay = 0,
+ .idle_wait_delay = 17,
+ .elastic_limit = 16,
+ .term_range_adj = 6,
+ .xcvr_setup = 15,
+ .xcvr_lsfslew = 2,
+ .xcvr_lsrslew = 2,
+ },
+};
+
+static struct tegra_usb_platform_data tegra_ehci3_utmi_pdata = {
+ .port_otg = false,
+ .has_hostpc = false,
+ .phy_intf = TEGRA_USB_PHY_INTF_UTMI,
+ .op_mode = TEGRA_USB_OPMODE_HOST,
+ .u_data.host = {
+ .vbus_gpio = -1,
+ .vbus_reg = NULL,
+ .hot_plug = true,
+ .remote_wakeup_supported = true,
+ .power_off_on_suspend = false,
+ },
+ .u_cfg.utmi = {
+ .hssync_start_delay = 0,
+ .idle_wait_delay = 17,
+ .elastic_limit = 16,
+ .term_range_adj = 6,
+ .xcvr_setup = 8,
+ .xcvr_lsfslew = 2,
+ .xcvr_lsrslew = 2,
+ },
+};
static void __init p852_usb_init(void)
{
@@ -541,16 +589,16 @@ static void __init p852_usb_init(void)
else
*/
{
- tegra_ehci1_device.dev.platform_data = &tegra_ehci_pdata[0];
+ tegra_ehci1_device.dev.platform_data = &tegra_ehci1_utmi_pdata;
platform_device_register(&tegra_ehci1_device);
}
if (!(p852_sku_peripherals & P852_SKU_ULPI_DISABLE)) {
- tegra_ehci2_device.dev.platform_data = &tegra_ehci_pdata[1];
+ tegra_ehci2_device.dev.platform_data = &tegra_ehci_ulpi_link_pdata;
platform_device_register(&tegra_ehci2_device);
}
- tegra_ehci3_device.dev.platform_data = &tegra_ehci_pdata[2];
+ tegra_ehci3_device.dev.platform_data = &tegra_ehci3_utmi_pdata;
platform_device_register(&tegra_ehci3_device);
}
@@ -634,10 +682,6 @@ static void __init p852_uart_init(void)
}
}
-static struct platform_device generic_codec_driver = {
- .name = "generic-dit",
-};
-
static void __init p852_flash_init(void)
{
if (p852_sku_peripherals & P852_SKU_NAND_ENABLE)
diff --git a/arch/arm/mach-tegra/p852/board-p852.h b/arch/arm/mach-tegra/p852/board-p852.h
index bb43febb4a2c..8e8f1444029c 100644
--- a/arch/arm/mach-tegra/p852/board-p852.h
+++ b/arch/arm/mach-tegra/p852/board-p852.h
@@ -55,7 +55,6 @@
#include "../pm.h"
#include "../devices.h"
#include "../gpio-names.h"
-#include "../wakeups-t2.h"
#define P852_SKU3 0x030000UL
diff --git a/arch/arm/mach-tegra/pcie.c b/arch/arm/mach-tegra/pcie.c
index 22e60d56f3ca..ec386a51721c 100644
--- a/arch/arm/mach-tegra/pcie.c
+++ b/arch/arm/mach-tegra/pcie.c
@@ -36,6 +36,8 @@
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
+#include <linux/workqueue.h>
+#include <linux/gpio.h>
#include <asm/sizes.h>
#include <asm/mach/pci.h>
@@ -48,51 +50,6 @@
#define MSELECT_CONFIG_0_ENABLE_PCIE_APERTURE 5
-#define PINMUX_AUX_PEX_L0_RST_N_0 0x33bc
-#define PINMUX_AUX_PEX_L0_RST_N_0_E_INPUT 5
-#define PINMUX_AUX_PEX_L0_RST_N_0_E_INPUT_ENABLE 1
-
-#define PINMUX_AUX_PEX_L1_RST_N_0 0x33cc
-#define PINMUX_AUX_PEX_L1_RST_N_0_E_INPUT 5
-#define PINMUX_AUX_PEX_L1_RST_N_0_E_INPUT_ENABLE 1
-
-#define PINMUX_AUX_PEX_L2_RST_N_0 0x33d8
-#define PINMUX_AUX_PEX_L2_RST_N_0_E_INPUT 5
-#define PINMUX_AUX_PEX_L2_RST_N_0_E_INPUT_ENABLE 1
-#define AFI_PEX0_CTRL_0_PEX0_CLKREQ_EN 1
-#define NV_PCIE2_PADS_REFCLK_CFG1 0x000000cc
-#define APBDEV_PMC_SCRATCH42_0_PCX_CLAMP_MASK 0x1
-
-
-#define AFI_MSI_VEC0_0 0x6c
-#define AFI_MSI_VEC1_0 0x70
-#define AFI_MSI_VEC2_0 0x74
-#define AFI_MSI_VEC3_0 0x78
-#define AFI_MSI_VEC4_0 0x7c
-#define AFI_MSI_VEC5_0 0x80
-#define AFI_MSI_VEC6_0 0x84
-#define AFI_MSI_VEC7_0 0x88
-
-#define AFI_MSI_EN_VEC0_0 0x8c
-#define AFI_MSI_EN_VEC1_0 0x90
-#define AFI_MSI_EN_VEC2_0 0x94
-#define AFI_MSI_EN_VEC3_0 0x98
-#define AFI_MSI_EN_VEC4_0 0x9c
-#define AFI_MSI_EN_VEC5_0 0xa0
-#define AFI_MSI_EN_VEC6_0 0xa4
-#define AFI_MSI_EN_VEC7_0 0xa8
-
-#define AFI_MSI_FPCI_BAR_ST_0 0x64
-#define AFI_MSI_BAR_SZ_0 0x60
-#define AFI_MSI_AXI_BAR_ST_0 0x68
-#define AFI_INTR_MASK_0 0xb4
-#define AFI_INTR_MASK_0_INT_MASK 0
-#define AFI_INTR_MASK_0_MSI_MASK 8
-
-
-#define AFI_PEXBIAS_CTRL_0 0x168
-
-
/* register definitions */
#define AFI_OFFSET 0x3800
#define PADS_OFFSET 0x3000
@@ -128,6 +85,24 @@
#define AFI_MSI_FPCI_BAR_ST 0x64
#define AFI_MSI_AXI_BAR_ST 0x68
+#define AFI_MSI_VEC0_0 0x6c
+#define AFI_MSI_VEC1_0 0x70
+#define AFI_MSI_VEC2_0 0x74
+#define AFI_MSI_VEC3_0 0x78
+#define AFI_MSI_VEC4_0 0x7c
+#define AFI_MSI_VEC5_0 0x80
+#define AFI_MSI_VEC6_0 0x84
+#define AFI_MSI_VEC7_0 0x88
+
+#define AFI_MSI_EN_VEC0_0 0x8c
+#define AFI_MSI_EN_VEC1_0 0x90
+#define AFI_MSI_EN_VEC2_0 0x94
+#define AFI_MSI_EN_VEC3_0 0x98
+#define AFI_MSI_EN_VEC4_0 0x9c
+#define AFI_MSI_EN_VEC5_0 0xa0
+#define AFI_MSI_EN_VEC6_0 0xa4
+#define AFI_MSI_EN_VEC7_0 0xa8
+
#define AFI_CONFIGURATION 0xac
#define AFI_CONFIGURATION_EN_FPCI (1 << 0)
@@ -138,19 +113,19 @@
#define AFI_INTR_MASK_MSI_MASK (1 << 8)
#define AFI_INTR_CODE 0xb8
-#define AFI_INTR_CODE_MASK 0xf
-#define AFI_INTR_MASTER_ABORT 4
-#define AFI_INTR_LEGACY 6
+#define AFI_INTR_CODE_MASK 0xf
+#define AFI_INTR_MASTER_ABORT 4
+#define AFI_INTR_LEGACY 6
#define AFI_INTR_SIGNATURE 0xbc
#define AFI_SM_INTR_ENABLE 0xc4
#define AFI_AFI_INTR_ENABLE 0xc8
-#define AFI_INTR_EN_INI_SLVERR (1 << 0)
-#define AFI_INTR_EN_INI_DECERR (1 << 1)
-#define AFI_INTR_EN_TGT_SLVERR (1 << 2)
-#define AFI_INTR_EN_TGT_DECERR (1 << 3)
-#define AFI_INTR_EN_TGT_WRERR (1 << 4)
+#define AFI_INTR_EN_INI_SLVERR (1 << 0)
+#define AFI_INTR_EN_INI_DECERR (1 << 1)
+#define AFI_INTR_EN_TGT_SLVERR (1 << 2)
+#define AFI_INTR_EN_TGT_DECERR (1 << 3)
+#define AFI_INTR_EN_TGT_WRERR (1 << 4)
#define AFI_INTR_EN_DFPCI_DECERR (1 << 5)
#define AFI_INTR_EN_AXI_DECERR (1 << 6)
#define AFI_INTR_EN_FPCI_TIMEOUT (1 << 7)
@@ -172,8 +147,11 @@
#define AFI_PEX1_CTRL 0x118
#define AFI_PEX2_CTRL 0x128
#define AFI_PEX_CTRL_RST (1 << 0)
+#define AFI_PEX_CTRL_CLKREQ_EN (1 << 1)
#define AFI_PEX_CTRL_REFCLK_EN (1 << 3)
+#define AFI_PEXBIAS_CTRL_0 0x168
+
#define RP_VEND_XP 0x00000F00
#define RP_VEND_XP_DL_UP (1 << 30)
@@ -203,6 +181,8 @@
#define PADS_PLL_CTL_TXCLKREF_DIV10 (0 << 20)
#define PADS_PLL_CTL_TXCLKREF_DIV5 (1 << 20)
+#define PADS_REFCLK_CFG1 0x000000CC
+
/* PMC access is required for PCIE xclk (un)clamping */
#define PMC_SCRATCH42 0x144
#define PMC_SCRATCH42_PCX_CLAMP (1 << 0)
@@ -211,6 +191,9 @@
#define PCIE2_RP_PRIV_MISC_CTLR_CLK_CLAMP_ENABLE 1 << 23
#define PCIE2_RP_PRIV_MISC_TMS_CLK_CLAMP_ENABLE 1 << 31
+#define NV_PCIE2_RP_VEND_XP1 0x00000F04
+#define NV_PCIE2_RP_VEND_XP1_LINK_PVT_CTL_L1_ASPM_SUPPORT_ENABLE 1 << 21
+
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
/*
* Tegra2 defines 1GB in the AXI address map for PCIe.
@@ -280,7 +263,7 @@
*/
#define PCIE_IOMAP_SZ (PCIE_REGS_SZ + PCIE_CFG_SZ + PCIE_EXT_CFG_SZ)
-#define MMIO_BASE (TEGRA_PCIE_BASE + SZ_48M)
+#define MMIO_BASE (TEGRA_PCIE_BASE + PCIE_IOMAP_SZ)
#define MMIO_SIZE SZ_1M
#define MEM_BASE_0 (TEGRA_PCIE_BASE + SZ_256M)
#define MEM_SIZE SZ_256M
@@ -308,6 +291,7 @@ struct tegra_pcie_port {
char mem_space_name[16];
char prefetch_space_name[20];
struct resource res[3];
+ struct pci_bus* bus;
};
struct tegra_pcie_info {
@@ -319,6 +303,7 @@ struct tegra_pcie_info {
struct resource res_mmio;
int power_rails_enabled;
int pcie_power_enabled;
+ struct work_struct hotplug_detect;
struct regulator *regulator_hvdd;
struct regulator *regulator_pexio;
@@ -333,8 +318,6 @@ struct tegra_pcie_info {
#define pmc_readl(reg) \
__raw_readl((u32)reg_pmc_base + (reg))
-static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
-
static struct tegra_pcie_info tegra_pcie = {
.res_mmio = {
.name = "PCI IO",
@@ -350,14 +333,11 @@ static struct resource pcie_prefetch_mem_space;
/* disable read write while noirq operation
* is performed since pcie is powered off */
static bool is_pcie_noirq_op = false;
-/* used to backup config space registers of all pcie devices */
-static u32 *pbackup_config_space = NULL;
-static u16 *pbackup_pcie_cap_space = NULL;
-static u16 *pbackup_pcix_cap_space = NULL;
-/* use same save state and position variables to store pcie */
-/* and pcix capability offsets at even & odd index respectively */
-static struct pci_cap_saved_state **pcie_save_state;
-static int *pos;
+/* enable and init msi once during boot or resume */
+static bool msi_enable;
+/* this flag is used for enumeration by hotplug */
+/* when dock is not connected while system boot */
+static bool is_dock_conn_at_boot = true;
void __iomem *tegra_pcie_io_base;
EXPORT_SYMBOL(tegra_pcie_io_base);
@@ -549,7 +529,7 @@ static void __devinit tegra_pcie_relax_enable(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, tegra_pcie_relax_enable);
-static void __init tegra_pcie_preinit(void)
+static void tegra_pcie_preinit(void)
{
pcie_io_space.name = "PCIe I/O Space";
pcie_io_space.start = PCIBIOS_MIN_IO;
@@ -620,6 +600,83 @@ static struct hw_pci tegra_pcie_hw = {
.map_irq = tegra_pcie_map_irq,
};
+#ifdef CONFIG_PM
+static int tegra_pcie_suspend(struct device *dev);
+static int tegra_pcie_resume(struct device *dev);
+
+/* It enumerates the devices when dock is connected after system boot */
+/* this is similar to pcibios_init_hw in bios32.c */
+static void tegra_pcie_hotplug_init(void)
+{
+ struct pci_sys_data *sys = NULL;
+ int ret, nr;
+
+ if (is_dock_conn_at_boot)
+ return;
+
+ tegra_pcie_preinit();
+ for (nr = 0; nr < tegra_pcie_hw.nr_controllers; nr++) {
+ sys = kzalloc(sizeof(struct pci_sys_data), GFP_KERNEL);
+ if (!sys)
+ panic("PCI: unable to allocate sys data!");
+
+#ifdef CONFIG_PCI_DOMAINS
+ sys->domain = tegra_pcie_hw.domain;
+#endif
+ sys->hw = &tegra_pcie_hw;
+ sys->busnr = nr;
+ sys->swizzle = tegra_pcie_hw.swizzle;
+ sys->map_irq = tegra_pcie_hw.map_irq;
+ sys->resource[0] = &ioport_resource;
+ sys->resource[1] = &iomem_resource;
+ ret = tegra_pcie_setup(nr, sys);
+ if (ret > 0)
+ pci_create_bus(NULL, nr, &tegra_pcie_ops, sys);
+ }
+ is_dock_conn_at_boot = true;
+}
+#endif
+
+static void tegra_pcie_attach(void)
+{
+ /* this hardcode is just to bypass the check in resume */
+ if (!is_dock_conn_at_boot)
+ tegra_pcie.num_ports = 1;
+#ifdef CONFIG_PM
+ tegra_pcie_resume(NULL);
+#endif
+}
+
+static void tegra_pcie_detach(void)
+{
+#ifdef CONFIG_PM
+ tegra_pcie_suspend(NULL);
+#endif
+}
+
+static void work_hotplug_handler(struct work_struct *work)
+{
+ struct tegra_pcie_info *pcie_driver =
+ container_of(work, struct tegra_pcie_info, hotplug_detect);
+ int val;
+
+ if (pcie_driver->plat_data->gpio == -1)
+ return;
+ val = gpio_get_value(pcie_driver->plat_data->gpio);
+ if (val == 0) {
+ pr_info("Pcie Dock Connected\n");
+ tegra_pcie_attach();
+ } else {
+ pr_info("Pcie Dock DisConnected\n");
+ tegra_pcie_detach();
+ }
+}
+
+static irqreturn_t gpio_pcie_detect_isr(int irq, void *arg)
+{
+ schedule_work(&tegra_pcie.hotplug_detect);
+ return IRQ_HANDLED;
+}
static irqreturn_t tegra_pcie_isr(int irq, void *arg)
{
@@ -735,11 +792,9 @@ static void tegra_pcie_enable_controller(void)
{
u32 val, reg;
int i;
- void __iomem *reg_apb_misc_base;
void __iomem *reg_mselect_base;
- reg_apb_misc_base = IO_ADDRESS(TEGRA_APB_MISC_BASE);
- reg_mselect_base = IO_ADDRESS(TEGRA_MSELECT_BASE);
+ reg_mselect_base = IO_ADDRESS(TEGRA_MSELECT_BASE);
/* select the PCIE APERTURE in MSELECT config */
reg = readl(reg_mselect_base);
reg |= 1 << MSELECT_CONFIG_0_ENABLE_PCIE_APERTURE;
@@ -748,8 +803,7 @@ static void tegra_pcie_enable_controller(void)
/* Enable slot clock and pulse the reset signals */
for (i = 0, reg = AFI_PEX0_CTRL; i < MAX_PCIE_SUPPORTED_PORTS;
i++, reg += (i*8)) {
- val = afi_readl(reg) | AFI_PEX_CTRL_REFCLK_EN |
- (1 << AFI_PEX0_CTRL_0_PEX0_CLKREQ_EN);
+ val = afi_readl(reg) | AFI_PEX_CTRL_CLKREQ_EN | AFI_PEX_CTRL_REFCLK_EN;
afi_writel(val, reg);
val &= ~AFI_PEX_CTRL_RST;
afi_writel(val, reg);
@@ -759,7 +813,8 @@ static void tegra_pcie_enable_controller(void)
}
afi_writel(0, AFI_PEXBIAS_CTRL_0);
- /* Enable dual controller and both ports */
+ /* Enable all PCIE controller and */
+ /* system management configuration of PCIE crossbar */
val = afi_readl(AFI_PCIE_CONFIG);
val &= ~(AFI_PCIE_CONFIG_PCIEC0_DISABLE_DEVICE |
AFI_PCIE_CONFIG_PCIEC1_DISABLE_DEVICE |
@@ -772,6 +827,7 @@ static void tegra_pcie_enable_controller(void)
#endif
afi_writel(val, AFI_PCIE_CONFIG);
+ /* Disable Gen 2 capability of PCIE */
val = afi_readl(AFI_FUSE) & ~AFI_FUSE_PCIE_T0_GEN2_DIS;
afi_writel(val, AFI_FUSE);
@@ -784,15 +840,15 @@ static void tegra_pcie_enable_controller(void)
/*
* set up PHY PLL inputs select PLLE output as refclock,
- * set TX ref sel to div10 (not div5)
+ * set pll TX clock ref to div10 (not div5)
+ * set pll ref clock buf to enable.
*/
val = pads_readl(PADS_PLL_CTL);
val &= ~(PADS_PLL_CTL_REFCLK_MASK | PADS_PLL_CTL_TXCLKREF_MASK);
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
val |= (PADS_PLL_CTL_REFCLK_INTERNAL_CML | PADS_PLL_CTL_TXCLKREF_DIV10);
#else
- val |= (PADS_PLL_CTL_REFCLK_INTERNAL_CML |
- PADS_PLL_CTL_TXCLKREF_BUF_EN);
+ val |= (PADS_PLL_CTL_REFCLK_INTERNAL_CML | PADS_PLL_CTL_TXCLKREF_BUF_EN);
#endif
pads_writel(val, PADS_PLL_CTL);
@@ -805,7 +861,7 @@ static void tegra_pcie_enable_controller(void)
* This doesn't exist in the documentation
*/
pads_writel(0xfa5cfa5c, 0xc8);
- pads_writel(0x0000FA5C, NV_PCIE2_PADS_REFCLK_CFG1);
+ pads_writel(0x0000FA5C, PADS_REFCLK_CFG1);
/* Wait for the PLL to lock */
do {
@@ -844,7 +900,7 @@ static void tegra_pcie_enable_controller(void)
return;
}
-static int tegra_pci_enable_regulators(void)
+static int tegra_pcie_enable_regulators(void)
{
if (tegra_pcie.power_rails_enabled)
return 0;
@@ -897,7 +953,7 @@ static int tegra_pci_enable_regulators(void)
return 0;
}
-static int tegra_pci_disable_regulators(void)
+static int tegra_pcie_disable_regulators(void)
{
int err = 0;
if (tegra_pcie.power_rails_enabled == 0)
@@ -917,24 +973,36 @@ err_exit:
return err;
}
+static int tegra_pcie_power_regate(void)
+{
+ int err;
+ err = tegra_unpowergate_partition_with_clk_on(TEGRA_POWERGATE_PCIE);
+ if (err) {
+ pr_err("PCIE: powerup sequence failed: %d\n", err);
+ return err;
+ }
+ tegra_periph_reset_assert(tegra_pcie.pcie_xclk);
+ return clk_enable(tegra_pcie.pll_e);
+}
+
+#ifdef CONFIG_PM
static int tegra_pcie_power_on(void)
{
int err = 0;
if (tegra_pcie.pcie_power_enabled)
return 0;
- err = tegra_pci_enable_regulators();
+ err = tegra_pcie_enable_regulators();
if (err)
goto err_exit;
- err = tegra_unpowergate_partition_with_clk_on(TEGRA_POWERGATE_PCIE);
+ err = tegra_pcie_power_regate();
if (err)
goto err_exit;
- if (tegra_pcie.pll_e)
- clk_enable(tegra_pcie.pll_e);
tegra_pcie.pcie_power_enabled = 1;
err_exit:
return err;
}
+#endif
static int tegra_pcie_power_off(void)
{
@@ -948,25 +1016,13 @@ static int tegra_pcie_power_off(void)
if (err)
goto err_exit;
- err = tegra_pci_disable_regulators();
+ err = tegra_pcie_disable_regulators();
tegra_pcie.pcie_power_enabled = 0;
err_exit:
return err;
}
-static int tegra_pcie_power_regate(void)
-{
- int err;
- err = tegra_unpowergate_partition_with_clk_on(TEGRA_POWERGATE_PCIE);
- if (err) {
- pr_err("PCIE: powerup sequence failed: %d\n", err);
- return err;
- }
- tegra_periph_reset_assert(tegra_pcie.pcie_xclk);
- return clk_enable(tegra_pcie.pll_e);
-}
-
static int tegra_pcie_clocks_get(void)
{
/* reset the PCIEXCLK */
@@ -999,8 +1055,9 @@ static int tegra_pcie_get_resources(void)
{
struct resource *res_mmio = 0;
int err;
+
tegra_pcie.power_rails_enabled = 0;
- err = tegra_pci_enable_regulators();
+ err = tegra_pcie_enable_regulators();
if (err) {
pr_err("PCIE: failed to enable power rails %d\n", err);
goto err_pwr_on_rail;
@@ -1019,6 +1076,7 @@ static int tegra_pcie_get_resources(void)
goto err_pwr_on;
}
+ /* Allocate config space virtual memory */
tegra_pcie.regs = ioremap_nocache(TEGRA_PCIE_BASE, PCIE_IOMAP_SZ);
if (tegra_pcie.regs == NULL) {
pr_err("PCIE: Failed to map PCI/AFI registers\n");
@@ -1033,6 +1091,7 @@ static int tegra_pcie_get_resources(void)
goto err_req_io;
}
+ /* Allocate downstream IO virtual memory */
tegra_pcie_io_base = ioremap_nocache(res_mmio->start,
resource_size(res_mmio));
if (tegra_pcie_io_base == NULL) {
@@ -1062,7 +1121,7 @@ err_map_reg:
err_pwr_on:
tegra_pcie_clocks_put();
err_pwr_on_rail:
- tegra_pci_disable_regulators();
+ tegra_pcie_disable_regulators();
return err;
}
@@ -1108,19 +1167,20 @@ static bool tegra_pcie_check_link(struct tegra_pcie_port *pp, int idx,
}
retry:
- /* Pulse the PEX reset */
- reg = afi_readl(reset_reg) & ~AFI_PEX_CTRL_RST;
- afi_writel(reg, reset_reg);
- reg = afi_readl(reset_reg) | AFI_PEX_CTRL_RST;
- afi_writel(reg, reset_reg);
+ if (--retries) {
+ /* Pulse the PEX reset */
+ reg = afi_readl(reset_reg) & ~AFI_PEX_CTRL_RST;
+ afi_writel(reg, reset_reg);
+ reg = afi_readl(reset_reg) | AFI_PEX_CTRL_RST;
+ afi_writel(reg, reset_reg);
+ }
- retries--;
} while (retries);
return false;
}
-static void tegra_enable_clock_clamp(int index)
+static void tegra_pcie_enable_clock_clamp(int index)
{
unsigned int data;
@@ -1132,6 +1192,16 @@ static void tegra_enable_clock_clamp(int index)
rp_writel(data, NV_PCIE2_RP_PRIV_MISC, index);
}
+static void tegra_pcie_enable_aspm_l1_support(int index)
+{
+ unsigned int data;
+
+ /* Enable ASPM - L1 state support by default */
+ data = rp_readl(NV_PCIE2_RP_VEND_XP1, index);
+ data |= (NV_PCIE2_RP_VEND_XP1_LINK_PVT_CTL_L1_ASPM_SUPPORT_ENABLE);
+ rp_writel(data, NV_PCIE2_RP_VEND_XP1, index);
+}
+
static void tegra_pcie_add_port(int index, u32 offset, u32 reset_reg)
{
struct tegra_pcie_port *pp;
@@ -1147,10 +1217,10 @@ static void tegra_pcie_add_port(int index, u32 offset, u32 reset_reg)
printk(KERN_INFO "PCIE: port %d: link down, ignoring\n", index);
return;
}
- tegra_enable_clock_clamp(index);
+ tegra_pcie_enable_clock_clamp(index);
+ tegra_pcie_enable_aspm_l1_support(index);
tegra_pcie.num_ports++;
pp->index = index;
- pp->root_bus_nr = -1;
memset(pp->res, 0, sizeof(pp->res));
}
@@ -1168,6 +1238,8 @@ static int tegra_pcie_init(void)
pcibios_min_mem = 0x03000000ul;
pcibios_min_io = 0x10000000ul;
#endif
+
+ INIT_WORK(&tegra_pcie.hotplug_detect, work_hotplug_handler);
err = tegra_pcie_get_resources();
if (err)
return err;
@@ -1177,61 +1249,51 @@ static int tegra_pcie_init(void)
tegra_pcie_setup_translations();
for (port = 0; port < MAX_PCIE_SUPPORTED_PORTS; port++) {
ctrl_offset += (port * 8);
- rp_offset = (rp_offset + 0x1000) * port;
+ rp_offset = (rp_offset + RP_OFFSET) * port;
if (tegra_pcie.plat_data->port_status[port])
tegra_pcie_add_port(port, rp_offset, ctrl_offset);
}
tegra_pcie.pcie_power_enabled = 1;
+ if (tegra_pcie.plat_data->use_dock_detect) {
+ unsigned int irq;
+
+ pr_info("acquiring dock_detect = %d\n",
+ tegra_pcie.plat_data->gpio);
+ gpio_request(tegra_pcie.plat_data->gpio, "pcie_dock_detect");
+ gpio_direction_input(tegra_pcie.plat_data->gpio);
+ irq = gpio_to_irq(tegra_pcie.plat_data->gpio);
+ if (irq < 0) {
+ pr_err("Unable to get irq number for dock_detect\n");
+ goto err_irq;
+ }
+ err = request_irq(irq,
+ gpio_pcie_detect_isr,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ "pcie_dock_detect",
+ (void *)tegra_pcie.plat_data);
+ if (err < 0) {
+ pr_err("Unable to claim irq number for dock_detect\n");
+ goto err_irq;
+ }
+ }
+
if (tegra_pcie.num_ports)
pci_common_init(&tegra_pcie_hw);
- else
+ else {
+ /* no dock is connected, hotplug will occur after boot */
err = tegra_pcie_power_off();
+ is_dock_conn_at_boot = false;
+ }
- return err;
-}
-
-static int tegra_pcie_allocate_config_states(int ndev, int size)
-{
- /* backup config space registers of all devices since it gets reset in
- save state call from suspend noirq due to disabling of read in it */
- pbackup_config_space = kzalloc(ndev*size*sizeof(u32), GFP_KERNEL);
- if (!pbackup_config_space)
- return -ENODEV;
- pbackup_pcie_cap_space = kzalloc(ndev*PCIE_CTRL_REGS*sizeof(u16), GFP_KERNEL);
- if (!pbackup_pcie_cap_space)
- return -ENODEV;
- pbackup_pcix_cap_space = kzalloc(ndev*sizeof(u16), GFP_KERNEL);
- if (!pbackup_pcix_cap_space)
- return -ENODEV;
- pcie_save_state = kzalloc(COMBINE_PCIE_PCIX_SPACE*ndev*
- sizeof(struct pci_cap_saved_state*), GFP_KERNEL);
- if (!pbackup_pcix_cap_space)
- return -ENODEV;
- pos = kzalloc(COMBINE_PCIE_PCIX_SPACE*ndev*sizeof(int), GFP_KERNEL);
- if (!pos)
- return -ENODEV;
-
- return 0;
-}
+err_irq:
-static void tegra_pcie_deallocate_config_states(void)
-{
- if (pbackup_config_space)
- kzfree(pbackup_config_space);
- if (pbackup_pcie_cap_space)
- kzfree(pbackup_pcie_cap_space);
- if (pbackup_pcix_cap_space)
- kzfree(pbackup_pcix_cap_space);
- if (pcie_save_state)
- kzfree(pcie_save_state);
- if (pos)
- kzfree(pos);
+ return err;
}
-static int tegra_pci_probe(struct platform_device *pdev)
+static int tegra_pcie_probe(struct platform_device *pdev)
{
- int ret, size = 0, ndev = 0;
+ int ret;
struct pci_dev *dev = NULL;
tegra_pcie.plat_data = pdev->dev.platform_data;
@@ -1245,92 +1307,24 @@ static int tegra_pci_probe(struct platform_device *pdev)
/* disable async PM of pci devices to ensure right order */
/* suspend/resume calls of tegra and bus driver */
- for_each_pci_dev(dev){
+ for_each_pci_dev(dev)
device_disable_async_suspend(&dev->dev);
- size = sizeof(dev->saved_config_space) / sizeof(u32);
- ndev++;
- }
- tegra_pcie_allocate_config_states(ndev, size);
return ret;
}
-static int tegra_pcie_save_state(struct pci_dev *pdev, int ndev)
-{
- int size;
-
- /*save pcie control registers */
- pos[ndev] = pci_pcie_cap(pdev);
- if (pos[ndev]){
- pcie_save_state[ndev] = pci_find_saved_cap(pdev, PCI_CAP_ID_EXP);
- if (!pcie_save_state[ndev]) {
- dev_err(&pdev->dev, "buffer not found in %s\n", __func__);
- return -ENOMEM;
- }
- memcpy(&pbackup_pcie_cap_space[PCIE_CTRL_REGS*(ndev/2)],
- pcie_save_state[ndev]->cap.data, PCIE_CTRL_REGS*sizeof(u16));
- }
- /* save pcix state */
- pos[ndev+1] = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
- if (pos[ndev+1] > 0){
- pcie_save_state[ndev+1] = pci_find_saved_cap(pdev, PCI_CAP_ID_PCIX);
- if (!pcie_save_state[ndev+1]) {
- dev_err(&pdev->dev, "buffer not found in %s\n", __func__);
- return -ENOMEM;
- }
- memcpy(&pbackup_pcix_cap_space[ndev/2],
- pcie_save_state[ndev+1]->cap.data, sizeof(u16));
- }
- /* save config space registers */
- size = sizeof(pdev->saved_config_space) / sizeof(u32);
- memcpy(&pbackup_config_space[size*ndev/2],
- pdev->saved_config_space, size*sizeof(u32));
-
- return 0;
-}
-
-static void tegra_pcie_restore_state(struct pci_dev *pdev, int ndev)
-{
- int size;
-
- /* restore pcie control registers */
- if (pcie_save_state[ndev] && (pos[ndev] > 0))
- memcpy(pcie_save_state[ndev]->cap.data,
- &pbackup_pcie_cap_space[PCIE_CTRL_REGS*(ndev/2)],
- PCIE_CTRL_REGS*sizeof(u16));
-
- /* restore pcix state */
- if (pcie_save_state[ndev+1] && (pos[ndev+1] > 0))
- memcpy(pcie_save_state[ndev+1]->cap.data,
- &pbackup_pcix_cap_space[ndev/2], sizeof(u16));
-
- /* restore config space registers */
- size = sizeof(pdev->saved_config_space) / sizeof(u32);
- memcpy(pdev->saved_config_space,
- &pbackup_config_space[size*ndev/2], size*sizeof(u32));
-}
-
-static int tegra_pci_suspend(struct device *dev)
+#ifdef CONFIG_PM
+static int tegra_pcie_suspend(struct device *dev)
{
- int ret = 0, ndev = 0;
+ int ret = 0;
struct pci_dev *pdev = NULL;
if (!tegra_pcie.num_ports)
return ret;
for_each_pci_dev(pdev) {
- /* save state of pcie devices before powering off regulators */
- pci_save_state(pdev);
- if (!pdev->subordinate)
- pci_prepare_to_sleep(pdev);
- }
-
- for_each_pci_dev(pdev) {
- /* save control and config space registers*/
- ret = tegra_pcie_save_state(pdev, ndev*2);
- if (ret < 0)
- return ret;
- ndev++;
+ pci_remove_bus_device(pdev);
+ break;
}
/* disable read/write registers before powering off */
@@ -1338,83 +1332,110 @@ static int tegra_pci_suspend(struct device *dev)
return tegra_pcie_power_off();
}
-static int tegra_pci_resume_noirq(struct device *dev)
-{
- struct pci_dev *pdev = NULL;
- /* set this flag to avoid restore state in resume noirq */
- for_each_pci_dev(pdev)
- pdev->state_saved = 0;
-
- return 0;
+static void tegra_pcie_set_irq(struct pci_bus *bus)
+{
+ struct pci_bus *b;
+ struct pci_dev *pdev;
+
+ list_for_each_entry(pdev, &bus->devices, bus_list) {
+ b = pdev->subordinate;
+ if (!b) {
+ pdev->irq = tegra_pcie_map_irq(pdev,0,0);
+ pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, pdev->irq);
+ continue;
+ }
+ tegra_pcie_set_irq(b);
+ pdev->irq = tegra_pcie_map_irq(pdev,0,0);
+ pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, pdev->irq);
+ }
}
-static int tegra_pci_resume(struct device *dev)
+static int tegra_pcie_resume(struct device *dev)
{
- int ret = 0, ndev = 0;
- struct pci_dev *pdev = NULL;
- int port;
+ int ret = 0;
+ struct pci_bus *bus = NULL;
+ int port, rp_offset = 0;
+ int ctrl_offset = AFI_PEX0_CTRL;
if (!tegra_pcie.num_ports)
return ret;
+
ret = tegra_pcie_power_on();
/* enable read/write registers after powering on */
is_pcie_noirq_op = false;
tegra_pcie_enable_controller();
tegra_pcie_setup_translations();
+ msi_enable = false;
- for (port = 0; port < MAX_PCIE_SUPPORTED_PORTS; port++)
+ /* reset number of ports before adding port */
+ tegra_pcie.num_ports = 0;
+ for (port = 0; port < MAX_PCIE_SUPPORTED_PORTS; port++) {
+ ctrl_offset += (port * 8);
+ rp_offset = (rp_offset + 0x1000) * port;
if (tegra_pcie.plat_data->port_status[port])
- tegra_enable_clock_clamp(port);
+ tegra_pcie_add_port(port, rp_offset, ctrl_offset);
+ }
- for_each_pci_dev(pdev) {
- /* restore control and config space registers*/
- tegra_pcie_restore_state(pdev, ndev*2);
- /* set this flag to force restore state in resume */
- pdev->state_saved = 1;
- ndev++;
+ tegra_pcie_hotplug_init();
+ while ((bus = pci_find_next_bus(bus)) != NULL) {
+ struct pci_dev *dev;
+
+ pci_scan_child_bus(bus);
+
+ list_for_each_entry(dev, &bus->devices, bus_list)
+ if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
+ dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
+ if (dev->subordinate)
+ pci_bus_size_bridges(dev->subordinate);
+
+ /* set irq for all devices */
+ tegra_pcie_set_irq(bus);
+ pci_bus_assign_resources(bus);
+ pci_enable_bridges(bus);
+ pci_bus_add_devices(bus);
}
return ret;
}
+#endif
-static int tegra_pci_remove(struct platform_device *pdev)
+static int tegra_pcie_remove(struct platform_device *pdev)
{
- tegra_pcie_deallocate_config_states();
return 0;
}
+
#ifdef CONFIG_PM
-static const struct dev_pm_ops tegra_pci_pm_ops = {
- .suspend = tegra_pci_suspend,
- .resume = tegra_pci_resume,
- .resume_noirq = tegra_pci_resume_noirq,
+static const struct dev_pm_ops tegra_pcie_pm_ops = {
+ .suspend = tegra_pcie_suspend,
+ .resume = tegra_pcie_resume,
};
#endif
-static struct platform_driver tegra_pci_driver = {
- .probe = tegra_pci_probe,
- .remove = tegra_pci_remove,
+static struct platform_driver tegra_pcie_driver = {
+ .probe = tegra_pcie_probe,
+ .remove = tegra_pcie_remove,
.driver = {
.name = "tegra-pcie",
.owner = THIS_MODULE,
#ifdef CONFIG_PM
- .pm = &tegra_pci_pm_ops,
+ .pm = &tegra_pcie_pm_ops,
#endif
},
};
-static int __init tegra_pci_init_driver(void)
+static int __init tegra_pcie_init_driver(void)
{
- return platform_driver_register(&tegra_pci_driver);
+ return platform_driver_register(&tegra_pcie_driver);
}
-static void __exit tegra_pci_exit_driver(void)
+static void __exit tegra_pcie_exit_driver(void)
{
- platform_driver_unregister(&tegra_pci_driver);
+ platform_driver_unregister(&tegra_pcie_driver);
}
-module_init(tegra_pci_init_driver);
-module_exit(tegra_pci_exit_driver);
+module_init(tegra_pcie_init_driver);
+module_exit(tegra_pcie_exit_driver);
static struct irq_chip tegra_irq_chip_msi_pcie = {
.name = "PCIe-MSI",
@@ -1478,7 +1499,7 @@ void msi_map_release(struct msi_map_entry *entry)
}
}
-static irqreturn_t pci_tegra_msi_isr(int irq, void *arg)
+static irqreturn_t tegra_pcie_msi_isr(int irq, void *arg)
{
int i;
int offset;
@@ -1510,31 +1531,28 @@ static irqreturn_t pci_tegra_msi_isr(int irq, void *arg)
return IRQ_HANDLED;
}
-static bool pci_tegra_enable_msi(void)
+static bool tegra_pcie_enable_msi(void)
{
bool retval = false;
- static bool already_done;
u32 reg;
u32 msi_base = 0;
u32 msi_aligned = 0;
- /* enables MSI interrupts. */
/* this only happens once. */
- if (already_done) {
+ if (msi_enable) {
retval = true;
goto exit;
}
-
msi_map_init();
- if (request_irq(INT_PCIE_MSI, pci_tegra_msi_isr,
+ /* enables MSI interrupts. */
+ if (request_irq(INT_PCIE_MSI, tegra_pcie_msi_isr,
IRQF_SHARED, "PCIe-MSI",
- pci_tegra_msi_isr)) {
+ tegra_pcie_msi_isr)) {
pr_err("%s: Cannot register IRQ %u\n",
__func__, INT_PCIE_MSI);
goto exit;
}
-
/* setup AFI/FPCI range */
/* FIXME do this better! should be based on PAGE_SIZE */
msi_base = __get_free_pages(GFP_KERNEL, 3);
@@ -1542,14 +1560,14 @@ static bool pci_tegra_enable_msi(void)
msi_aligned = virt_to_phys((void *)msi_aligned);
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- afi_writel(msi_aligned, AFI_MSI_FPCI_BAR_ST_0);
+ afi_writel(msi_aligned, AFI_MSI_FPCI_BAR_ST);
#else
/* different from T20!*/
- afi_writel(msi_aligned>>8, AFI_MSI_FPCI_BAR_ST_0);
+ afi_writel(msi_aligned>>8, AFI_MSI_FPCI_BAR_ST);
#endif
- afi_writel(msi_aligned, AFI_MSI_AXI_BAR_ST_0);
+ afi_writel(msi_aligned, AFI_MSI_AXI_BAR_ST);
/* this register is in 4K increments */
- afi_writel(1, AFI_MSI_BAR_SZ_0);
+ afi_writel(1, AFI_MSI_BAR_SZ);
/* enable all MSI vectors */
afi_writel(0xffffffff, AFI_MSI_EN_VEC0_0);
@@ -1563,13 +1581,12 @@ static bool pci_tegra_enable_msi(void)
/* and unmask the MSI interrupt */
reg = 0;
- reg |= ((1 << AFI_INTR_MASK_0_INT_MASK) |
- (1 << AFI_INTR_MASK_0_MSI_MASK));
- afi_writel(reg, AFI_INTR_MASK_0);
+ reg |= (AFI_INTR_MASK_INT_MASK | AFI_INTR_MASK_MSI_MASK);
+ afi_writel(reg, AFI_INTR_MASK);
set_irq_flags(INT_PCIE_MSI, IRQF_VALID);
- already_done = true;
+ msi_enable = true;
retval = true;
exit:
if (!retval) {
@@ -1587,7 +1604,7 @@ int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
struct msi_msg msg;
struct msi_map_entry *map_entry = NULL;
- if (!pci_tegra_enable_msi())
+ if (!tegra_pcie_enable_msi())
goto exit;
map_entry = msi_map_get();
@@ -1602,7 +1619,7 @@ int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
irq_set_msi_desc(map_entry->irq, desc);
set_irq_flags(map_entry->irq, IRQF_VALID);
- msg.address_lo = afi_readl(AFI_MSI_AXI_BAR_ST_0);
+ msg.address_lo = afi_readl(AFI_MSI_AXI_BAR_ST);
/* 32 bit address only */
msg.address_hi = 0;
msg.data = map_entry->index;
diff --git a/arch/arm/mach-tegra/pinmux-t2-tables.c b/arch/arm/mach-tegra/pinmux-t2-tables.c
index 3a39f45cb57e..32e55421c583 100644
--- a/arch/arm/mach-tegra/pinmux-t2-tables.c
+++ b/arch/arm/mach-tegra/pinmux-t2-tables.c
@@ -195,9 +195,9 @@ const struct tegra_drive_pingroup_desc tegra_soc_drive_pingroups[TEGRA_MAX_DRIVE
PINGROUP(LM0, PW0, LCD, DISPLAYA, DISPLAYB, SPI3, RSVD, RSVD4, 0x1C, 24, 0x90, 26, 0xAC, 22),\
PINGROUP(LM1, PW1, LCD, DISPLAYA, DISPLAYB, RSVD, CRT, RSVD3, 0x1C, 25, 0x90, 28, 0xAC, 22),\
PINGROUP(LPP, PM7, LCD, DISPLAYA, DISPLAYB, RSVD, RSVD, RSVD4, 0x20, 8, 0x98, 14, 0xAC, 18),\
- PINGROUP(LPW0, PB2, LCD, DISPLAYA, DISPLAYB, SPI3, HDMI, DISPLAYA, 0x20, 3, 0x90, 0, 0xAC, 20),\
+ PINGROUP(LPW0, PB2, LCD, DISPLAYA, DISPLAYB, SPI3, HDMI, DISPLAYB, 0x20, 3, 0x90, 0, 0xAC, 20),\
PINGROUP(LPW1, PC1, LCD, DISPLAYA, DISPLAYB, RSVD, RSVD, RSVD4, 0x20, 4, 0x90, 2, 0xAC, 20),\
- PINGROUP(LPW2, PC6, LCD, DISPLAYA, DISPLAYB, SPI3, HDMI, DISPLAYA, 0x20, 5, 0x90, 4, 0xAC, 20),\
+ PINGROUP(LPW2, PC6, LCD, DISPLAYA, DISPLAYB, SPI3, HDMI, DISPLAYB, 0x20, 5, 0x90, 4, 0xAC, 20),\
PINGROUP(LSC0, PB3, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 27, 0x90, 18, 0xAC, 22),\
PINGROUP(LSC1, PZ3, LCD, DISPLAYA, DISPLAYB, SPI3, HDMI, DISPLAYA, 0x1C, 28, 0x90, 20, 0xAC, 20),\
PINGROUP(LSCK, PZ4, LCD, DISPLAYA, DISPLAYB, SPI3, HDMI, DISPLAYA, 0x1C, 29, 0x90, 16, 0xAC, 20),\
diff --git a/arch/arm/mach-tegra/pinmux-t3-tables.c b/arch/arm/mach-tegra/pinmux-t3-tables.c
index 282a34bdd0d3..09729a4cfbae 100644
--- a/arch/arm/mach-tegra/pinmux-t3-tables.c
+++ b/arch/arm/mach-tegra/pinmux-t3-tables.c
@@ -3,7 +3,7 @@
*
* Common pinmux configurations for Tegra 3 SoCs
*
- * Copyright (C) 2010-2011 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 of the GNU General Public License as published by
@@ -64,11 +64,16 @@
const struct tegra_drive_pingroup_desc tegra_soc_drive_pingroups[TEGRA_MAX_DRIVE_PINGROUP] = {
DEFAULT_DRIVE_PINGROUP(AO1, 0x868),
DEFAULT_DRIVE_PINGROUP(AO2, 0x86c),
- DEFAULT_DRIVE_PINGROUP(AT1, 0x870),
- DEFAULT_DRIVE_PINGROUP(AT2, 0x874),
- DEFAULT_DRIVE_PINGROUP(AT3, 0x878),
- DEFAULT_DRIVE_PINGROUP(AT4, 0x87c),
- DEFAULT_DRIVE_PINGROUP(AT5, 0x880),
+ SET_DRIVE_PINGROUP(AT1, 0x870, 14, 0x1f, 19, 0x1f,
+ 24, 0x3, 28, 0x3),
+ SET_DRIVE_PINGROUP(AT2, 0x874, 14, 0x1f, 19, 0x1f,
+ 24, 0x3, 28, 0x3),
+ SET_DRIVE_PINGROUP(AT3, 0x878, 14, 0x1f, 19, 0x1f,
+ 28, 0x3, 30, 0x3),
+ SET_DRIVE_PINGROUP(AT4, 0x87c, 14, 0x1f, 19, 0x1f,
+ 28, 0x3, 30, 0x3),
+ SET_DRIVE_PINGROUP(AT5, 0x880, 14, 0x1f, 19, 0x1f,
+ 28, 0x3, 30, 0x3),
DEFAULT_DRIVE_PINGROUP(CDEV1, 0x884),
DEFAULT_DRIVE_PINGROUP(CDEV2, 0x888),
DEFAULT_DRIVE_PINGROUP(CSUS, 0x88c),
@@ -101,10 +106,14 @@ const struct tegra_drive_pingroup_desc tegra_soc_drive_pingroups[TEGRA_MAX_DRIVE
24, 0xf, 28, 0xf),
SET_DRIVE_PINGROUP(GMD, 0x90c, 14, 0x1f, 19, 0x1f,
24, 0xf, 28, 0xf),
- DEFAULT_DRIVE_PINGROUP(GME, 0x910),
- DEFAULT_DRIVE_PINGROUP(GMF, 0x914),
- DEFAULT_DRIVE_PINGROUP(GMG, 0x918),
- DEFAULT_DRIVE_PINGROUP(GMH, 0x91c),
+ SET_DRIVE_PINGROUP(GME, 0x910, 14, 0x1f, 19, 0x1f,
+ 28, 0x3, 30, 0x3),
+ SET_DRIVE_PINGROUP(GMF, 0x914, 14, 0x1f, 19, 0x1f,
+ 28, 0x3, 30, 0x3),
+ SET_DRIVE_PINGROUP(GMG, 0x918, 14, 0x1f, 19, 0x1f,
+ 28, 0x3, 30, 0x3),
+ SET_DRIVE_PINGROUP(GMH, 0x91c, 14, 0x1f, 19, 0x1f,
+ 28, 0x3, 30, 0x3),
DEFAULT_DRIVE_PINGROUP(OWR, 0x920),
DEFAULT_DRIVE_PINGROUP(UAD, 0x924),
DEFAULT_DRIVE_PINGROUP(GPV, 0x928),
@@ -140,166 +149,166 @@ const struct tegra_drive_pingroup_desc tegra_soc_drive_pingroups[TEGRA_MAX_DRIVE
#define PINGROUPS \
/* NAME GPIO VDD f0 f1 f2 f3 fSafe io reg */\
- PINGROUP(ULPI_DATA0, PO1, BB, SPI3, HSI, UARTA, ULPI, RSVD, INPUT, 0x3000),\
- PINGROUP(ULPI_DATA1, PO2, BB, SPI3, HSI, UARTA, ULPI, RSVD, INPUT, 0x3004),\
- PINGROUP(ULPI_DATA2, PO3, BB, SPI3, HSI, UARTA, ULPI, RSVD, INPUT, 0x3008),\
- PINGROUP(ULPI_DATA3, PO4, BB, SPI3, HSI, UARTA, ULPI, RSVD, INPUT, 0x300c),\
- PINGROUP(ULPI_DATA4, PO5, BB, SPI2, HSI, UARTA, ULPI, RSVD, INPUT, 0x3010),\
- PINGROUP(ULPI_DATA5, PO6, BB, SPI2, HSI, UARTA, ULPI, RSVD, INPUT, 0x3014),\
- PINGROUP(ULPI_DATA6, PO7, BB, SPI2, HSI, UARTA, ULPI, RSVD, INPUT, 0x3018),\
- PINGROUP(ULPI_DATA7, PO0, BB, SPI2, HSI, UARTA, ULPI, RSVD, INPUT, 0x301c),\
- PINGROUP(ULPI_CLK, PY0, BB, SPI1, RSVD, UARTD, ULPI, RSVD, INPUT, 0x3020),\
- PINGROUP(ULPI_DIR, PY1, BB, SPI1, RSVD, UARTD, ULPI, RSVD, INPUT, 0x3024),\
- PINGROUP(ULPI_NXT, PY2, BB, SPI1, RSVD, UARTD, ULPI, RSVD, INPUT, 0x3028),\
- PINGROUP(ULPI_STP, PY3, BB, SPI1, RSVD, UARTD, ULPI, RSVD, INPUT, 0x302c),\
- PINGROUP(DAP3_FS, PP0, BB, I2S2, RSVD1, DISPLAYA, DISPLAYB, RSVD, INPUT, 0x3030),\
- PINGROUP(DAP3_DIN, PP1, BB, I2S2, RSVD1, DISPLAYA, DISPLAYB, RSVD, INPUT, 0x3034),\
- PINGROUP(DAP3_DOUT, PP2, BB, I2S2, RSVD1, DISPLAYA, DISPLAYB, RSVD, INPUT, 0x3038),\
- PINGROUP(DAP3_SCLK, PP3, BB, I2S2, RSVD1, DISPLAYA, DISPLAYB, RSVD, INPUT, 0x303c),\
+ PINGROUP(ULPI_DATA0, PO1, BB, SPI3, HSI, UARTA, ULPI, ULPI, INPUT, 0x3000),\
+ PINGROUP(ULPI_DATA1, PO2, BB, SPI3, HSI, UARTA, ULPI, ULPI, INPUT, 0x3004),\
+ PINGROUP(ULPI_DATA2, PO3, BB, SPI3, HSI, UARTA, ULPI, ULPI, INPUT, 0x3008),\
+ PINGROUP(ULPI_DATA3, PO4, BB, SPI3, HSI, UARTA, ULPI, ULPI, INPUT, 0x300c),\
+ PINGROUP(ULPI_DATA4, PO5, BB, SPI2, HSI, UARTA, ULPI, ULPI, INPUT, 0x3010),\
+ PINGROUP(ULPI_DATA5, PO6, BB, SPI2, HSI, UARTA, ULPI, ULPI, INPUT, 0x3014),\
+ PINGROUP(ULPI_DATA6, PO7, BB, SPI2, HSI, UARTA, ULPI, ULPI, INPUT, 0x3018),\
+ PINGROUP(ULPI_DATA7, PO0, BB, SPI2, HSI, UARTA, ULPI, ULPI, INPUT, 0x301c),\
+ PINGROUP(ULPI_CLK, PY0, BB, SPI1, RSVD, UARTD, ULPI, ULPI, INPUT, 0x3020),\
+ PINGROUP(ULPI_DIR, PY1, BB, SPI1, RSVD, UARTD, ULPI, ULPI, INPUT, 0x3024),\
+ PINGROUP(ULPI_NXT, PY2, BB, SPI1, RSVD, UARTD, ULPI, ULPI, INPUT, 0x3028),\
+ PINGROUP(ULPI_STP, PY3, BB, SPI1, RSVD, UARTD, ULPI, ULPI, INPUT, 0x302c),\
+ PINGROUP(DAP3_FS, PP0, BB, I2S2, RSVD1, DISPLAYA, DISPLAYB, I2S2, INPUT, 0x3030),\
+ PINGROUP(DAP3_DIN, PP1, BB, I2S2, RSVD1, DISPLAYA, DISPLAYB, I2S2, INPUT, 0x3034),\
+ PINGROUP(DAP3_DOUT, PP2, BB, I2S2, RSVD1, DISPLAYA, DISPLAYB, I2S2, INPUT, 0x3038),\
+ PINGROUP(DAP3_SCLK, PP3, BB, I2S2, RSVD1, DISPLAYA, DISPLAYB, I2S2, INPUT, 0x303c),\
PINGROUP(GPIO_PV0, PV0, BB, RSVD, RSVD, RSVD, RSVD, RSVD, INPUT, 0x3040),\
PINGROUP(GPIO_PV1, PV1, BB, RSVD, RSVD, RSVD, RSVD, RSVD, INPUT, 0x3044),\
- PINGROUP(SDMMC1_CLK, PZ0, SDMMC1, SDMMC1, RSVD1, RSVD2, INVALID, RSVD, INPUT, 0x3048),\
- PINGROUP(SDMMC1_CMD, PZ1, SDMMC1, SDMMC1, RSVD1, RSVD2, INVALID, RSVD, INPUT, 0x304c),\
- PINGROUP(SDMMC1_DAT3, PY4, SDMMC1, SDMMC1, RSVD1, UARTE, INVALID, RSVD, INPUT, 0x3050),\
- PINGROUP(SDMMC1_DAT2, PY5, SDMMC1, SDMMC1, RSVD1, UARTE, INVALID, RSVD, INPUT, 0x3054),\
- PINGROUP(SDMMC1_DAT1, PY6, SDMMC1, SDMMC1, RSVD1, UARTE, INVALID, RSVD, INPUT, 0x3058),\
- PINGROUP(SDMMC1_DAT0, PY7, SDMMC1, SDMMC1, RSVD1, UARTE, INVALID, RSVD, INPUT, 0x305c),\
+ PINGROUP(SDMMC1_CLK, PZ0, SDMMC1, SDMMC1, RSVD1, RSVD2, INVALID, SDMMC1, INPUT, 0x3048),\
+ PINGROUP(SDMMC1_CMD, PZ1, SDMMC1, SDMMC1, RSVD1, RSVD2, INVALID, SDMMC1, INPUT, 0x304c),\
+ PINGROUP(SDMMC1_DAT3, PY4, SDMMC1, SDMMC1, RSVD1, UARTE, INVALID, SDMMC1, INPUT, 0x3050),\
+ PINGROUP(SDMMC1_DAT2, PY5, SDMMC1, SDMMC1, RSVD1, UARTE, INVALID, SDMMC1, INPUT, 0x3054),\
+ PINGROUP(SDMMC1_DAT1, PY6, SDMMC1, SDMMC1, RSVD1, UARTE, INVALID, SDMMC1, INPUT, 0x3058),\
+ PINGROUP(SDMMC1_DAT0, PY7, SDMMC1, SDMMC1, RSVD1, UARTE, INVALID, SDMMC1, INPUT, 0x305c),\
PINGROUP(GPIO_PV2, PV2, SDMMC1, OWR, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x3060),\
PINGROUP(GPIO_PV3, PV3, SDMMC1, INVALID, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x3064),\
- PINGROUP(CLK2_OUT, PW5, SDMMC1, EXTPERIPH2, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x3068),\
- PINGROUP(CLK2_REQ, PCC5, SDMMC1, DAP, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x306c),\
- PINGROUP(LCD_PWR1, PC1, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x3070),\
- PINGROUP(LCD_PWR2, PC6, LCD, DISPLAYA, DISPLAYB, SPI5, INVALID, RSVD, OUTPUT, 0x3074),\
- PINGROUP(LCD_SDIN, PZ2, LCD, DISPLAYA, DISPLAYB, SPI5, RSVD, RSVD, OUTPUT, 0x3078),\
- PINGROUP(LCD_SDOUT, PN5, LCD, DISPLAYA, DISPLAYB, SPI5, INVALID, RSVD, OUTPUT, 0x307c),\
- PINGROUP(LCD_WR_N, PZ3, LCD, DISPLAYA, DISPLAYB, SPI5, INVALID, RSVD, OUTPUT, 0x3080),\
- PINGROUP(LCD_CS0_N, PN4, LCD, DISPLAYA, DISPLAYB, SPI5, RSVD, RSVD, OUTPUT, 0x3084),\
- PINGROUP(LCD_DC0, PN6, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x3088),\
- PINGROUP(LCD_SCK, PZ4, LCD, DISPLAYA, DISPLAYB, SPI5, INVALID, RSVD, OUTPUT, 0x308c),\
- PINGROUP(LCD_PWR0, PB2, LCD, DISPLAYA, DISPLAYB, SPI5, INVALID, RSVD, OUTPUT, 0x3090),\
- PINGROUP(LCD_PCLK, PB3, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x3094),\
- PINGROUP(LCD_DE, PJ1, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x3098),\
- PINGROUP(LCD_HSYNC, PJ3, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x309c),\
- PINGROUP(LCD_VSYNC, PJ4, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30a0),\
- PINGROUP(LCD_D0, PE0, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30a4),\
- PINGROUP(LCD_D1, PE1, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30a8),\
- PINGROUP(LCD_D2, PE2, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30ac),\
- PINGROUP(LCD_D3, PE3, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30b0),\
- PINGROUP(LCD_D4, PE4, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30b4),\
- PINGROUP(LCD_D5, PE5, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30b8),\
- PINGROUP(LCD_D6, PE6, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30bc),\
- PINGROUP(LCD_D7, PE7, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30c0),\
- PINGROUP(LCD_D8, PF0, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30c4),\
- PINGROUP(LCD_D9, PF1, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30c8),\
- PINGROUP(LCD_D10, PF2, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30cc),\
- PINGROUP(LCD_D11, PF3, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30d0),\
- PINGROUP(LCD_D12, PF4, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30d4),\
- PINGROUP(LCD_D13, PF5, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30d8),\
- PINGROUP(LCD_D14, PF6, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30dc),\
- PINGROUP(LCD_D15, PF7, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30e0),\
- PINGROUP(LCD_D16, PM0, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30e4),\
- PINGROUP(LCD_D17, PM1, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30e8),\
- PINGROUP(LCD_D18, PM2, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30ec),\
- PINGROUP(LCD_D19, PM3, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30f0),\
- PINGROUP(LCD_D20, PM4, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30f4),\
- PINGROUP(LCD_D21, PM5, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30f8),\
- PINGROUP(LCD_D22, PM6, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30fc),\
- PINGROUP(LCD_D23, PM7, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x3100),\
- PINGROUP(LCD_CS1_N, PW0, LCD, DISPLAYA, DISPLAYB, SPI5, RSVD2, RSVD, OUTPUT, 0x3104),\
- PINGROUP(LCD_M1, PW1, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x3108),\
- PINGROUP(LCD_DC1, PD2, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x310c),\
+ PINGROUP(CLK2_OUT, PW5, SDMMC1, EXTPERIPH2, RSVD1, RSVD2, RSVD3, EXTPERIPH2, INPUT, 0x3068),\
+ PINGROUP(CLK2_REQ, PCC5, SDMMC1, DAP, RSVD1, RSVD2, RSVD3, DAP, INPUT, 0x306c),\
+ PINGROUP(LCD_PWR1, PC1, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x3070),\
+ PINGROUP(LCD_PWR2, PC6, LCD, DISPLAYA, DISPLAYB, SPI5, INVALID, DISPLAYA, OUTPUT, 0x3074),\
+ PINGROUP(LCD_SDIN, PZ2, LCD, DISPLAYA, DISPLAYB, SPI5, RSVD, DISPLAYA, OUTPUT, 0x3078),\
+ PINGROUP(LCD_SDOUT, PN5, LCD, DISPLAYA, DISPLAYB, SPI5, INVALID, DISPLAYA, OUTPUT, 0x307c),\
+ PINGROUP(LCD_WR_N, PZ3, LCD, DISPLAYA, DISPLAYB, SPI5, INVALID, DISPLAYA, OUTPUT, 0x3080),\
+ PINGROUP(LCD_CS0_N, PN4, LCD, DISPLAYA, DISPLAYB, SPI5, RSVD, DISPLAYA, OUTPUT, 0x3084),\
+ PINGROUP(LCD_DC0, PN6, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x3088),\
+ PINGROUP(LCD_SCK, PZ4, LCD, DISPLAYA, DISPLAYB, SPI5, INVALID, DISPLAYA, OUTPUT, 0x308c),\
+ PINGROUP(LCD_PWR0, PB2, LCD, DISPLAYA, DISPLAYB, SPI5, INVALID, DISPLAYA, OUTPUT, 0x3090),\
+ PINGROUP(LCD_PCLK, PB3, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x3094),\
+ PINGROUP(LCD_DE, PJ1, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x3098),\
+ PINGROUP(LCD_HSYNC, PJ3, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x309c),\
+ PINGROUP(LCD_VSYNC, PJ4, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30a0),\
+ PINGROUP(LCD_D0, PE0, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30a4),\
+ PINGROUP(LCD_D1, PE1, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30a8),\
+ PINGROUP(LCD_D2, PE2, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30ac),\
+ PINGROUP(LCD_D3, PE3, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30b0),\
+ PINGROUP(LCD_D4, PE4, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30b4),\
+ PINGROUP(LCD_D5, PE5, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30b8),\
+ PINGROUP(LCD_D6, PE6, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30bc),\
+ PINGROUP(LCD_D7, PE7, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30c0),\
+ PINGROUP(LCD_D8, PF0, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30c4),\
+ PINGROUP(LCD_D9, PF1, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30c8),\
+ PINGROUP(LCD_D10, PF2, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30cc),\
+ PINGROUP(LCD_D11, PF3, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30d0),\
+ PINGROUP(LCD_D12, PF4, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30d4),\
+ PINGROUP(LCD_D13, PF5, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30d8),\
+ PINGROUP(LCD_D14, PF6, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30dc),\
+ PINGROUP(LCD_D15, PF7, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30e0),\
+ PINGROUP(LCD_D16, PM0, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30e4),\
+ PINGROUP(LCD_D17, PM1, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30e8),\
+ PINGROUP(LCD_D18, PM2, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30ec),\
+ PINGROUP(LCD_D19, PM3, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30f0),\
+ PINGROUP(LCD_D20, PM4, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30f4),\
+ PINGROUP(LCD_D21, PM5, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30f8),\
+ PINGROUP(LCD_D22, PM6, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x30fc),\
+ PINGROUP(LCD_D23, PM7, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x3100),\
+ PINGROUP(LCD_CS1_N, PW0, LCD, DISPLAYA, DISPLAYB, SPI5, RSVD2, DISPLAYA, OUTPUT, 0x3104),\
+ PINGROUP(LCD_M1, PW1, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x3108),\
+ PINGROUP(LCD_DC1, PD2, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, DISPLAYA, OUTPUT, 0x310c),\
PINGROUP(HDMI_INT, PN7, LCD, RSVD, RSVD, RSVD, RSVD, RSVD, INPUT, 0x3110),\
- PINGROUP(DDC_SCL, PV4, LCD, I2C4, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x3114),\
- PINGROUP(DDC_SDA, PV5, LCD, I2C4, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x3118),\
- PINGROUP(CRT_HSYNC, PV6, LCD, CRT, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x311c),\
- PINGROUP(CRT_VSYNC, PV7, LCD, CRT, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x3120),\
- PINGROUP(VI_D0, PT4, VI, INVALID, RSVD1, VI, RSVD2, RSVD, INPUT, 0x3124),\
- PINGROUP(VI_D1, PD5, VI, INVALID, SDMMC2, VI, RSVD1, RSVD, INPUT, 0x3128),\
- PINGROUP(VI_D2, PL0, VI, INVALID, SDMMC2, VI, RSVD1, RSVD, INPUT, 0x312c),\
- PINGROUP(VI_D3, PL1, VI, INVALID, SDMMC2, VI, RSVD1, RSVD, INPUT, 0x3130),\
- PINGROUP(VI_D4, PL2, VI, INVALID, SDMMC2, VI, RSVD1, RSVD, INPUT, 0x3134),\
- PINGROUP(VI_D5, PL3, VI, INVALID, SDMMC2, VI, RSVD1, RSVD, INPUT, 0x3138),\
- PINGROUP(VI_D6, PL4, VI, INVALID, SDMMC2, VI, RSVD1, RSVD, INPUT, 0x313c),\
- PINGROUP(VI_D7, PL5, VI, INVALID, SDMMC2, VI, RSVD1, RSVD, INPUT, 0x3140),\
- PINGROUP(VI_D8, PL6, VI, INVALID, SDMMC2, VI, RSVD1, RSVD, INPUT, 0x3144),\
- PINGROUP(VI_D9, PL7, VI, INVALID, SDMMC2, VI, RSVD1, RSVD, INPUT, 0x3148),\
- PINGROUP(VI_D10, PT2, VI, INVALID, RSVD1, VI, RSVD2, RSVD, INPUT, 0x314c),\
- PINGROUP(VI_D11, PT3, VI, INVALID, RSVD1, VI, RSVD2, RSVD, INPUT, 0x3150),\
- PINGROUP(VI_PCLK, PT0, VI, RSVD1, SDMMC2, VI, RSVD2, RSVD, INPUT, 0x3154),\
+ PINGROUP(DDC_SCL, PV4, LCD, I2C4, RSVD1, RSVD2, RSVD3, I2C4, INPUT, 0x3114),\
+ PINGROUP(DDC_SDA, PV5, LCD, I2C4, RSVD1, RSVD2, RSVD3, I2C4, INPUT, 0x3118),\
+ PINGROUP(CRT_HSYNC, PV6, LCD, CRT, RSVD1, RSVD2, RSVD3, CRT, INPUT, 0x311c),\
+ PINGROUP(CRT_VSYNC, PV7, LCD, CRT, RSVD1, RSVD2, RSVD3, CRT, INPUT, 0x3120),\
+ PINGROUP(VI_D0, PT4, VI, INVALID, RSVD1, VI, RSVD2, VI, INPUT, 0x3124),\
+ PINGROUP(VI_D1, PD5, VI, INVALID, SDMMC2, VI, RSVD1, VI, INPUT, 0x3128),\
+ PINGROUP(VI_D2, PL0, VI, INVALID, SDMMC2, VI, RSVD1, VI, INPUT, 0x312c),\
+ PINGROUP(VI_D3, PL1, VI, INVALID, SDMMC2, VI, RSVD1, VI, INPUT, 0x3130),\
+ PINGROUP(VI_D4, PL2, VI, INVALID, SDMMC2, VI, RSVD1, VI, INPUT, 0x3134),\
+ PINGROUP(VI_D5, PL3, VI, INVALID, SDMMC2, VI, RSVD1, VI, INPUT, 0x3138),\
+ PINGROUP(VI_D6, PL4, VI, INVALID, SDMMC2, VI, RSVD1, VI, INPUT, 0x313c),\
+ PINGROUP(VI_D7, PL5, VI, INVALID, SDMMC2, VI, RSVD1, VI, INPUT, 0x3140),\
+ PINGROUP(VI_D8, PL6, VI, INVALID, SDMMC2, VI, RSVD1, VI, INPUT, 0x3144),\
+ PINGROUP(VI_D9, PL7, VI, INVALID, SDMMC2, VI, RSVD1, VI, INPUT, 0x3148),\
+ PINGROUP(VI_D10, PT2, VI, INVALID, RSVD1, VI, RSVD2, VI, INPUT, 0x314c),\
+ PINGROUP(VI_D11, PT3, VI, INVALID, RSVD1, VI, RSVD2, VI, INPUT, 0x3150),\
+ PINGROUP(VI_PCLK, PT0, VI, RSVD1, SDMMC2, VI, RSVD2, VI, INPUT, 0x3154),\
PINGROUP(VI_MCLK, PT1, VI, INVALID, INVALID, INVALID, VI, RSVD, INPUT, 0x3158),\
- PINGROUP(VI_VSYNC, PD6, VI, INVALID, RSVD1, VI, RSVD2, RSVD, INPUT, 0x315c),\
- PINGROUP(VI_HSYNC, PD7, VI, INVALID, RSVD1, VI, RSVD2, RSVD, INPUT, 0x3160),\
- PINGROUP(UART2_RXD, PC3, UART, IRDA, SPDIF, UARTA, SPI4, RSVD, INPUT, 0x3164),\
- PINGROUP(UART2_TXD, PC2, UART, IRDA, SPDIF, UARTA, SPI4, RSVD, INPUT, 0x3168),\
- PINGROUP(UART2_RTS_N, PJ6, UART, UARTA, UARTB, GMI, SPI4, RSVD, INPUT, 0x316c),\
- PINGROUP(UART2_CTS_N, PJ5, UART, UARTA, UARTB, GMI, SPI4, RSVD, INPUT, 0x3170),\
- PINGROUP(UART3_TXD, PW6, UART, UARTC, RSVD1, GMI, RSVD2, RSVD, INPUT, 0x3174),\
- PINGROUP(UART3_RXD, PW7, UART, UARTC, RSVD1, GMI, RSVD2, RSVD, INPUT, 0x3178),\
- PINGROUP(UART3_CTS_N, PA1, UART, UARTC, RSVD1, GMI, RSVD2, RSVD, INPUT, 0x317c),\
- PINGROUP(UART3_RTS_N, PC0, UART, UARTC, PWM0, GMI, RSVD2, RSVD, INPUT, 0x3180),\
- PINGROUP(GPIO_PU0, PU0, UART, OWR, UARTA, GMI, RSVD1, RSVD, INPUT, 0x3184),\
- PINGROUP(GPIO_PU1, PU1, UART, RSVD1, UARTA, GMI, RSVD2, RSVD, INPUT, 0x3188),\
- PINGROUP(GPIO_PU2, PU2, UART, RSVD1, UARTA, GMI, RSVD2, RSVD, INPUT, 0x318c),\
- PINGROUP(GPIO_PU3, PU3, UART, PWM0, UARTA, GMI, RSVD1, RSVD, INPUT, 0x3190),\
- PINGROUP(GPIO_PU4, PU4, UART, PWM1, UARTA, GMI, RSVD1, RSVD, INPUT, 0x3194),\
- PINGROUP(GPIO_PU5, PU5, UART, PWM2, UARTA, GMI, RSVD1, RSVD, INPUT, 0x3198),\
- PINGROUP(GPIO_PU6, PU6, UART, PWM3, UARTA, GMI, RSVD1, RSVD, INPUT, 0x319c),\
- PINGROUP(GEN1_I2C_SDA, PC5, UART, I2C1, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x31a0),\
- PINGROUP(GEN1_I2C_SCL, PC4, UART, I2C1, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x31a4),\
- PINGROUP(DAP4_FS, PP4, UART, I2S3, RSVD1, GMI, RSVD2, RSVD, INPUT, 0x31a8),\
- PINGROUP(DAP4_DIN, PP5, UART, I2S3, RSVD1, GMI, RSVD2, RSVD, INPUT, 0x31ac),\
- PINGROUP(DAP4_DOUT, PP6, UART, I2S3, RSVD1, GMI, RSVD2, RSVD, INPUT, 0x31b0),\
- PINGROUP(DAP4_SCLK, PP7, UART, I2S3, RSVD1, GMI, RSVD2, RSVD, INPUT, 0x31b4),\
- PINGROUP(CLK3_OUT, PEE0, UART, EXTPERIPH3, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x31b8),\
- PINGROUP(CLK3_REQ, PEE1, UART, DEV3, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x31bc),\
- PINGROUP(GMI_WP_N, PC7, GMI, RSVD1, NAND, GMI, GMI_ALT, RSVD, INPUT, 0x31c0),\
- PINGROUP(GMI_IORDY, PI5, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x31c4),\
- PINGROUP(GMI_WAIT, PI7, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x31c8),\
- PINGROUP(GMI_ADV_N, PK0, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x31cc),\
- PINGROUP(GMI_CLK, PK1, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x31d0),\
- PINGROUP(GMI_CS0_N, PJ0, GMI, RSVD1, NAND, GMI, DTV, RSVD, INPUT, 0x31d4),\
- PINGROUP(GMI_CS1_N, PJ2, GMI, RSVD1, NAND, GMI, DTV, RSVD, INPUT, 0x31d8),\
- PINGROUP(GMI_CS2_N, PK3, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x31dc),\
- PINGROUP(GMI_CS3_N, PK4, GMI, RSVD1, NAND, GMI, GMI_ALT, RSVD, INPUT, 0x31e0),\
- PINGROUP(GMI_CS4_N, PK2, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x31e4),\
- PINGROUP(GMI_CS6_N, PI3, GMI, NAND, NAND_ALT, GMI, SATA, RSVD, INPUT, 0x31e8),\
- PINGROUP(GMI_CS7_N, PI6, GMI, NAND, NAND_ALT, GMI, GMI_ALT, RSVD, INPUT, 0x31ec),\
- PINGROUP(GMI_AD0, PG0, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x31f0),\
- PINGROUP(GMI_AD1, PG1, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x31f4),\
- PINGROUP(GMI_AD2, PG2, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x31f8),\
- PINGROUP(GMI_AD3, PG3, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x31fc),\
- PINGROUP(GMI_AD4, PG4, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x3200),\
- PINGROUP(GMI_AD5, PG5, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x3204),\
- PINGROUP(GMI_AD6, PG6, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x3208),\
- PINGROUP(GMI_AD7, PG7, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x320c),\
- PINGROUP(GMI_AD8, PH0, GMI, PWM0, NAND, GMI, RSVD2, RSVD, INPUT, 0x3210),\
- PINGROUP(GMI_AD9, PH1, GMI, PWM1, NAND, GMI, RSVD2, RSVD, INPUT, 0x3214),\
- PINGROUP(GMI_AD10, PH2, GMI, PWM2, NAND, GMI, RSVD2, RSVD, INPUT, 0x3218),\
- PINGROUP(GMI_AD11, PH3, GMI, PWM3, NAND, GMI, RSVD2, RSVD, INPUT, 0x321c),\
- PINGROUP(GMI_AD12, PH4, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x3220),\
- PINGROUP(GMI_AD13, PH5, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x3224),\
- PINGROUP(GMI_AD14, PH6, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x3228),\
- PINGROUP(GMI_AD15, PH7, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x322c),\
- PINGROUP(GMI_A16, PJ7, GMI, UARTD, SPI4, GMI, GMI_ALT, RSVD, INPUT, 0x3230),\
- PINGROUP(GMI_A17, PB0, GMI, UARTD, SPI4, GMI, DTV, RSVD, INPUT, 0x3234),\
- PINGROUP(GMI_A18, PB1, GMI, UARTD, SPI4, GMI, DTV, RSVD, INPUT, 0x3238),\
- PINGROUP(GMI_A19, PK7, GMI, UARTD, SPI4, GMI, RSVD3, RSVD, INPUT, 0x323c),\
- PINGROUP(GMI_WR_N, PI0, GMI, RSVD1, NAND, GMI, RSVD3, RSVD, INPUT, 0x3240),\
- PINGROUP(GMI_OE_N, PI1, GMI, RSVD1, NAND, GMI, RSVD3, RSVD, INPUT, 0x3244),\
- PINGROUP(GMI_DQS, PI2, GMI, RSVD1, NAND, GMI, RSVD3, RSVD, INPUT, 0x3248),\
- PINGROUP(GMI_RST_N, PI4, GMI, NAND, NAND_ALT, GMI, RSVD3, RSVD, INPUT, 0x324c),\
- PINGROUP(GEN2_I2C_SCL, PT5, GMI, I2C2, INVALID, GMI, RSVD3, RSVD, INPUT, 0x3250),\
- PINGROUP(GEN2_I2C_SDA, PT6, GMI, I2C2, INVALID, GMI, RSVD3, RSVD, INPUT, 0x3254),\
- PINGROUP(SDMMC4_CLK, PCC4, SDMMC4, INVALID, NAND, GMI, SDMMC4, RSVD, INPUT, 0x3258),\
- PINGROUP(SDMMC4_CMD, PT7, SDMMC4, I2C3, NAND, GMI, SDMMC4, RSVD, INPUT, 0x325c),\
- PINGROUP(SDMMC4_DAT0, PAA0, SDMMC4, UARTE, SPI3, GMI, SDMMC4, RSVD, INPUT, 0x3260),\
- PINGROUP(SDMMC4_DAT1, PAA1, SDMMC4, UARTE, SPI3, GMI, SDMMC4, RSVD, INPUT, 0x3264),\
- PINGROUP(SDMMC4_DAT2, PAA2, SDMMC4, UARTE, SPI3, GMI, SDMMC4, RSVD, INPUT, 0x3268),\
- PINGROUP(SDMMC4_DAT3, PAA3, SDMMC4, UARTE, SPI3, GMI, SDMMC4, RSVD, INPUT, 0x326c),\
- PINGROUP(SDMMC4_DAT4, PAA4, SDMMC4, I2C3, I2S4, GMI, SDMMC4, RSVD, INPUT, 0x3270),\
- PINGROUP(SDMMC4_DAT5, PAA5, SDMMC4, VGP3, I2S4, GMI, SDMMC4, RSVD, INPUT, 0x3274),\
- PINGROUP(SDMMC4_DAT6, PAA6, SDMMC4, VGP4, I2S4, GMI, SDMMC4, RSVD, INPUT, 0x3278),\
- PINGROUP(SDMMC4_DAT7, PAA7, SDMMC4, VGP5, I2S4, GMI, SDMMC4, RSVD, INPUT, 0x327c),\
+ PINGROUP(VI_VSYNC, PD6, VI, INVALID, RSVD1, VI, RSVD2, VI, INPUT, 0x315c),\
+ PINGROUP(VI_HSYNC, PD7, VI, INVALID, RSVD1, VI, RSVD2, VI, INPUT, 0x3160),\
+ PINGROUP(UART2_RXD, PC3, UART, IRDA, SPDIF, UARTA, SPI4, IRDA, INPUT, 0x3164),\
+ PINGROUP(UART2_TXD, PC2, UART, IRDA, SPDIF, UARTA, SPI4, IRDA, INPUT, 0x3168),\
+ PINGROUP(UART2_RTS_N, PJ6, UART, UARTA, UARTB, GMI, SPI4, UARTB, INPUT, 0x316c),\
+ PINGROUP(UART2_CTS_N, PJ5, UART, UARTA, UARTB, GMI, SPI4, UARTB, INPUT, 0x3170),\
+ PINGROUP(UART3_TXD, PW6, UART, UARTC, RSVD1, GMI, RSVD2, UARTC, INPUT, 0x3174),\
+ PINGROUP(UART3_RXD, PW7, UART, UARTC, RSVD1, GMI, RSVD2, UARTC, INPUT, 0x3178),\
+ PINGROUP(UART3_CTS_N, PA1, UART, UARTC, RSVD1, GMI, RSVD2, UARTC, INPUT, 0x317c),\
+ PINGROUP(UART3_RTS_N, PC0, UART, UARTC, PWM0, GMI, RSVD2, UARTC, INPUT, 0x3180),\
+ PINGROUP(GPIO_PU0, PU0, UART, OWR, UARTA, GMI, RSVD1, GMI, INPUT, 0x3184),\
+ PINGROUP(GPIO_PU1, PU1, UART, RSVD1, UARTA, GMI, RSVD2, GMI, INPUT, 0x3188),\
+ PINGROUP(GPIO_PU2, PU2, UART, RSVD1, UARTA, GMI, RSVD2, GMI, INPUT, 0x318c),\
+ PINGROUP(GPIO_PU3, PU3, UART, PWM0, UARTA, GMI, RSVD1, GMI, INPUT, 0x3190),\
+ PINGROUP(GPIO_PU4, PU4, UART, PWM1, UARTA, GMI, RSVD1, GMI, INPUT, 0x3194),\
+ PINGROUP(GPIO_PU5, PU5, UART, PWM2, UARTA, GMI, RSVD1, GMI, INPUT, 0x3198),\
+ PINGROUP(GPIO_PU6, PU6, UART, PWM3, UARTA, GMI, RSVD1, GMI, INPUT, 0x319c),\
+ PINGROUP(GEN1_I2C_SDA, PC5, UART, I2C1, RSVD1, RSVD2, RSVD3, I2C1, INPUT, 0x31a0),\
+ PINGROUP(GEN1_I2C_SCL, PC4, UART, I2C1, RSVD1, RSVD2, RSVD3, I2C1, INPUT, 0x31a4),\
+ PINGROUP(DAP4_FS, PP4, UART, I2S3, RSVD1, GMI, RSVD2, I2S3, INPUT, 0x31a8),\
+ PINGROUP(DAP4_DIN, PP5, UART, I2S3, RSVD1, GMI, RSVD2, I2S3, INPUT, 0x31ac),\
+ PINGROUP(DAP4_DOUT, PP6, UART, I2S3, RSVD1, GMI, RSVD2, I2S3, INPUT, 0x31b0),\
+ PINGROUP(DAP4_SCLK, PP7, UART, I2S3, RSVD1, GMI, RSVD2, I2S3, INPUT, 0x31b4),\
+ PINGROUP(CLK3_OUT, PEE0, UART, EXTPERIPH3, RSVD1, RSVD2, RSVD3, EXTPERIPH3, INPUT, 0x31b8),\
+ PINGROUP(CLK3_REQ, PEE1, UART, DEV3, RSVD1, RSVD2, RSVD3, DEV3, INPUT, 0x31bc),\
+ PINGROUP(GMI_WP_N, PC7, GMI, RSVD1, NAND, GMI, GMI_ALT, GMI, INPUT, 0x31c0),\
+ PINGROUP(GMI_IORDY, PI5, GMI, RSVD1, NAND, GMI, RSVD2, GMI, INPUT, 0x31c4),\
+ PINGROUP(GMI_WAIT, PI7, GMI, RSVD1, NAND, GMI, RSVD2, NAND, INPUT, 0x31c8),\
+ PINGROUP(GMI_ADV_N, PK0, GMI, RSVD1, NAND, GMI, RSVD2, GMI, INPUT, 0x31cc),\
+ PINGROUP(GMI_CLK, PK1, GMI, RSVD1, NAND, GMI, RSVD2, GMI, INPUT, 0x31d0),\
+ PINGROUP(GMI_CS0_N, PJ0, GMI, RSVD1, NAND, GMI, DTV, GMI, INPUT, 0x31d4),\
+ PINGROUP(GMI_CS1_N, PJ2, GMI, RSVD1, NAND, GMI, DTV, GMI, INPUT, 0x31d8),\
+ PINGROUP(GMI_CS2_N, PK3, GMI, RSVD1, NAND, GMI, RSVD2, GMI, INPUT, 0x31dc),\
+ PINGROUP(GMI_CS3_N, PK4, GMI, RSVD1, NAND, GMI, GMI_ALT, GMI, INPUT, 0x31e0),\
+ PINGROUP(GMI_CS4_N, PK2, GMI, RSVD1, NAND, GMI, RSVD2, GMI, INPUT, 0x31e4),\
+ PINGROUP(GMI_CS6_N, PI3, GMI, NAND, NAND_ALT, GMI, SATA, NAND, INPUT, 0x31e8),\
+ PINGROUP(GMI_CS7_N, PI6, GMI, NAND, NAND_ALT, GMI, GMI_ALT, NAND, INPUT, 0x31ec),\
+ PINGROUP(GMI_AD0, PG0, GMI, RSVD1, NAND, GMI, RSVD2, GMI, INPUT, 0x31f0),\
+ PINGROUP(GMI_AD1, PG1, GMI, RSVD1, NAND, GMI, RSVD2, GMI, INPUT, 0x31f4),\
+ PINGROUP(GMI_AD2, PG2, GMI, RSVD1, NAND, GMI, RSVD2, GMI, INPUT, 0x31f8),\
+ PINGROUP(GMI_AD3, PG3, GMI, RSVD1, NAND, GMI, RSVD2, GMI, INPUT, 0x31fc),\
+ PINGROUP(GMI_AD4, PG4, GMI, RSVD1, NAND, GMI, RSVD2, GMI, INPUT, 0x3200),\
+ PINGROUP(GMI_AD5, PG5, GMI, RSVD1, NAND, GMI, RSVD2, GMI, INPUT, 0x3204),\
+ PINGROUP(GMI_AD6, PG6, GMI, RSVD1, NAND, GMI, RSVD2, GMI, INPUT, 0x3208),\
+ PINGROUP(GMI_AD7, PG7, GMI, RSVD1, NAND, GMI, RSVD2, GMI, INPUT, 0x320c),\
+ PINGROUP(GMI_AD8, PH0, GMI, PWM0, NAND, GMI, RSVD2, GMI, INPUT, 0x3210),\
+ PINGROUP(GMI_AD9, PH1, GMI, PWM1, NAND, GMI, RSVD2, GMI, INPUT, 0x3214),\
+ PINGROUP(GMI_AD10, PH2, GMI, PWM2, NAND, GMI, RSVD2, GMI, INPUT, 0x3218),\
+ PINGROUP(GMI_AD11, PH3, GMI, PWM3, NAND, GMI, RSVD2, GMI, INPUT, 0x321c),\
+ PINGROUP(GMI_AD12, PH4, GMI, RSVD1, NAND, GMI, RSVD2, GMI, INPUT, 0x3220),\
+ PINGROUP(GMI_AD13, PH5, GMI, RSVD1, NAND, GMI, RSVD2, GMI, INPUT, 0x3224),\
+ PINGROUP(GMI_AD14, PH6, GMI, RSVD1, NAND, GMI, RSVD2, GMI, INPUT, 0x3228),\
+ PINGROUP(GMI_AD15, PH7, GMI, RSVD1, NAND, GMI, RSVD2, GMI, INPUT, 0x322c),\
+ PINGROUP(GMI_A16, PJ7, GMI, UARTD, SPI4, GMI, GMI_ALT, GMI, INPUT, 0x3230),\
+ PINGROUP(GMI_A17, PB0, GMI, UARTD, SPI4, GMI, DTV, GMI, INPUT, 0x3234),\
+ PINGROUP(GMI_A18, PB1, GMI, UARTD, SPI4, GMI, DTV, GMI, INPUT, 0x3238),\
+ PINGROUP(GMI_A19, PK7, GMI, UARTD, SPI4, GMI, RSVD3, GMI, INPUT, 0x323c),\
+ PINGROUP(GMI_WR_N, PI0, GMI, RSVD1, NAND, GMI, RSVD3, GMI, INPUT, 0x3240),\
+ PINGROUP(GMI_OE_N, PI1, GMI, RSVD1, NAND, GMI, RSVD3, GMI, INPUT, 0x3244),\
+ PINGROUP(GMI_DQS, PI2, GMI, RSVD1, NAND, GMI, RSVD3, NAND, INPUT, 0x3248),\
+ PINGROUP(GMI_RST_N, PI4, GMI, NAND, NAND_ALT, GMI, RSVD3, NAND, INPUT, 0x324c),\
+ PINGROUP(GEN2_I2C_SCL, PT5, GMI, I2C2, INVALID, GMI, RSVD3, I2C2, INPUT, 0x3250),\
+ PINGROUP(GEN2_I2C_SDA, PT6, GMI, I2C2, INVALID, GMI, RSVD3, I2C2, INPUT, 0x3254),\
+ PINGROUP(SDMMC4_CLK, PCC4, SDMMC4, INVALID, NAND, GMI, SDMMC4, GMI, INPUT, 0x3258),\
+ PINGROUP(SDMMC4_CMD, PT7, SDMMC4, I2C3, NAND, GMI, SDMMC4, GMI, INPUT, 0x325c),\
+ PINGROUP(SDMMC4_DAT0, PAA0, SDMMC4, UARTE, SPI3, GMI, SDMMC4, GMI, INPUT, 0x3260),\
+ PINGROUP(SDMMC4_DAT1, PAA1, SDMMC4, UARTE, SPI3, GMI, SDMMC4, GMI, INPUT, 0x3264),\
+ PINGROUP(SDMMC4_DAT2, PAA2, SDMMC4, UARTE, SPI3, GMI, SDMMC4, GMI, INPUT, 0x3268),\
+ PINGROUP(SDMMC4_DAT3, PAA3, SDMMC4, UARTE, SPI3, GMI, SDMMC4, GMI, INPUT, 0x326c),\
+ PINGROUP(SDMMC4_DAT4, PAA4, SDMMC4, I2C3, I2S4, GMI, SDMMC4, GMI, INPUT, 0x3270),\
+ PINGROUP(SDMMC4_DAT5, PAA5, SDMMC4, VGP3, I2S4, GMI, SDMMC4, GMI, INPUT, 0x3274),\
+ PINGROUP(SDMMC4_DAT6, PAA6, SDMMC4, VGP4, I2S4, GMI, SDMMC4, GMI, INPUT, 0x3278),\
+ PINGROUP(SDMMC4_DAT7, PAA7, SDMMC4, VGP5, I2S4, GMI, SDMMC4, GMI, INPUT, 0x327c),\
PINGROUP(SDMMC4_RST_N, PCC3, SDMMC4, VGP6, RSVD1, RSVD2, POPSDMMC4, RSVD, INPUT, 0x3280),\
PINGROUP(CAM_MCLK, PCC0, CAM, VI, INVALID, VI_ALT2, POPSDMMC4, RSVD, INPUT, 0x3284),\
PINGROUP(GPIO_PCC1, PCC1, CAM, I2S4, RSVD1, RSVD2, POPSDMMC4, RSVD, INPUT, 0x3288),\
@@ -311,83 +320,83 @@ const struct tegra_drive_pingroup_desc tegra_soc_drive_pingroups[TEGRA_MAX_DRIVE
PINGROUP(GPIO_PBB5, PBB5, CAM, VGP5, DISPLAYA, DISPLAYB, POPSDMMC4, RSVD, INPUT, 0x32a0),\
PINGROUP(GPIO_PBB6, PBB6, CAM, VGP6, DISPLAYA, DISPLAYB, POPSDMMC4, RSVD, INPUT, 0x32a4),\
PINGROUP(GPIO_PBB7, PBB7, CAM, I2S4, RSVD1, RSVD2, POPSDMMC4, RSVD, INPUT, 0x32a8),\
- PINGROUP(GPIO_PCC2, PCC2, CAM, I2S4, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x32ac),\
- PINGROUP(JTAG_RTCK, PU7, SYS, RTCK, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x32b0),\
- PINGROUP(PWR_I2C_SCL, PZ6, SYS, I2CPWR, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x32b4),\
- PINGROUP(PWR_I2C_SDA, PZ7, SYS, I2CPWR, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x32b8),\
- PINGROUP(KB_ROW0, PR0, SYS, KBC, INVALID, RSVD2, RSVD3, RSVD, INPUT, 0x32bc),\
- PINGROUP(KB_ROW1, PR1, SYS, KBC, INVALID, RSVD2, RSVD3, RSVD, INPUT, 0x32c0),\
- PINGROUP(KB_ROW2, PR2, SYS, KBC, INVALID, RSVD2, RSVD3, RSVD, INPUT, 0x32c4),\
- PINGROUP(KB_ROW3, PR3, SYS, KBC, INVALID, RSVD2, INVALID, RSVD, INPUT, 0x32c8),\
- PINGROUP(KB_ROW4, PR4, SYS, KBC, INVALID, TRACE, RSVD3, RSVD, INPUT, 0x32cc),\
- PINGROUP(KB_ROW5, PR5, SYS, KBC, INVALID, TRACE, OWR, RSVD, INPUT, 0x32d0),\
- PINGROUP(KB_ROW6, PR6, SYS, KBC, INVALID, SDMMC2, INVALID, RSVD, INPUT, 0x32d4),\
- PINGROUP(KB_ROW7, PR7, SYS, KBC, INVALID, SDMMC2, INVALID, RSVD, INPUT, 0x32d8),\
- PINGROUP(KB_ROW8, PS0, SYS, KBC, INVALID, SDMMC2, INVALID, RSVD, INPUT, 0x32dc),\
- PINGROUP(KB_ROW9, PS1, SYS, KBC, INVALID, SDMMC2, INVALID, RSVD, INPUT, 0x32e0),\
- PINGROUP(KB_ROW10, PS2, SYS, KBC, INVALID, SDMMC2, INVALID, RSVD, INPUT, 0x32e4),\
- PINGROUP(KB_ROW11, PS3, SYS, KBC, INVALID, SDMMC2, INVALID, RSVD, INPUT, 0x32e8),\
- PINGROUP(KB_ROW12, PS4, SYS, KBC, INVALID, SDMMC2, INVALID, RSVD, INPUT, 0x32ec),\
- PINGROUP(KB_ROW13, PS5, SYS, KBC, INVALID, SDMMC2, INVALID, RSVD, INPUT, 0x32f0),\
- PINGROUP(KB_ROW14, PS6, SYS, KBC, INVALID, SDMMC2, INVALID, RSVD, INPUT, 0x32f4),\
- PINGROUP(KB_ROW15, PS7, SYS, KBC, INVALID, SDMMC2, INVALID, RSVD, INPUT, 0x32f8),\
- PINGROUP(KB_COL0, PQ0, SYS, KBC, INVALID, TRACE, INVALID, RSVD, INPUT, 0x32fc),\
- PINGROUP(KB_COL1, PQ1, SYS, KBC, INVALID, TRACE, INVALID, RSVD, INPUT, 0x3300),\
- PINGROUP(KB_COL2, PQ2, SYS, KBC, INVALID, TRACE, RSVD, RSVD, INPUT, 0x3304),\
- PINGROUP(KB_COL3, PQ3, SYS, KBC, INVALID, TRACE, RSVD, RSVD, INPUT, 0x3308),\
- PINGROUP(KB_COL4, PQ4, SYS, KBC, INVALID, TRACE, RSVD, RSVD, INPUT, 0x330c),\
- PINGROUP(KB_COL5, PQ5, SYS, KBC, INVALID, TRACE, RSVD, RSVD, INPUT, 0x3310),\
- PINGROUP(KB_COL6, PQ6, SYS, KBC, INVALID, TRACE, INVALID, RSVD, INPUT, 0x3314),\
- PINGROUP(KB_COL7, PQ7, SYS, KBC, INVALID, TRACE, INVALID, RSVD, INPUT, 0x3318),\
- PINGROUP(CLK_32K_OUT, PA0, SYS, BLINK, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x331c),\
- PINGROUP(SYS_CLK_REQ, PZ5, SYS, SYSCLK, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x3320),\
+ PINGROUP(GPIO_PCC2, PCC2, CAM, I2S4, RSVD1, RSVD2, POPSDMMC4, RSVD, INPUT, 0x32ac),\
+ PINGROUP(JTAG_RTCK, PU7, SYS, RTCK, RSVD1, RSVD2, RSVD3, RTCK, INPUT, 0x32b0),\
+ PINGROUP(PWR_I2C_SCL, PZ6, SYS, I2CPWR, RSVD1, RSVD2, RSVD3, I2CPWR, INPUT, 0x32b4),\
+ PINGROUP(PWR_I2C_SDA, PZ7, SYS, I2CPWR, RSVD1, RSVD2, RSVD3, I2CPWR, INPUT, 0x32b8),\
+ PINGROUP(KB_ROW0, PR0, SYS, KBC, INVALID, RSVD2, RSVD3, KBC, INPUT, 0x32bc),\
+ PINGROUP(KB_ROW1, PR1, SYS, KBC, INVALID, RSVD2, RSVD3, KBC, INPUT, 0x32c0),\
+ PINGROUP(KB_ROW2, PR2, SYS, KBC, INVALID, RSVD2, RSVD3, KBC, INPUT, 0x32c4),\
+ PINGROUP(KB_ROW3, PR3, SYS, KBC, INVALID, RSVD2, INVALID, KBC, INPUT, 0x32c8),\
+ PINGROUP(KB_ROW4, PR4, SYS, KBC, INVALID, TRACE, RSVD3, KBC, INPUT, 0x32cc),\
+ PINGROUP(KB_ROW5, PR5, SYS, KBC, INVALID, TRACE, OWR, KBC, INPUT, 0x32d0),\
+ PINGROUP(KB_ROW6, PR6, SYS, KBC, INVALID, SDMMC2, INVALID, KBC, INPUT, 0x32d4),\
+ PINGROUP(KB_ROW7, PR7, SYS, KBC, INVALID, SDMMC2, INVALID, KBC, INPUT, 0x32d8),\
+ PINGROUP(KB_ROW8, PS0, SYS, KBC, INVALID, SDMMC2, INVALID, KBC, INPUT, 0x32dc),\
+ PINGROUP(KB_ROW9, PS1, SYS, KBC, INVALID, SDMMC2, INVALID, KBC, INPUT, 0x32e0),\
+ PINGROUP(KB_ROW10, PS2, SYS, KBC, INVALID, SDMMC2, INVALID, KBC, INPUT, 0x32e4),\
+ PINGROUP(KB_ROW11, PS3, SYS, KBC, INVALID, SDMMC2, INVALID, KBC, INPUT, 0x32e8),\
+ PINGROUP(KB_ROW12, PS4, SYS, KBC, INVALID, SDMMC2, INVALID, KBC, INPUT, 0x32ec),\
+ PINGROUP(KB_ROW13, PS5, SYS, KBC, INVALID, SDMMC2, INVALID, KBC, INPUT, 0x32f0),\
+ PINGROUP(KB_ROW14, PS6, SYS, KBC, INVALID, SDMMC2, INVALID, KBC, INPUT, 0x32f4),\
+ PINGROUP(KB_ROW15, PS7, SYS, KBC, INVALID, SDMMC2, INVALID, KBC, INPUT, 0x32f8),\
+ PINGROUP(KB_COL0, PQ0, SYS, KBC, INVALID, TRACE, INVALID, KBC, INPUT, 0x32fc),\
+ PINGROUP(KB_COL1, PQ1, SYS, KBC, INVALID, TRACE, INVALID, KBC, INPUT, 0x3300),\
+ PINGROUP(KB_COL2, PQ2, SYS, KBC, INVALID, TRACE, RSVD, KBC, INPUT, 0x3304),\
+ PINGROUP(KB_COL3, PQ3, SYS, KBC, INVALID, TRACE, RSVD, KBC, INPUT, 0x3308),\
+ PINGROUP(KB_COL4, PQ4, SYS, KBC, INVALID, TRACE, RSVD, KBC, INPUT, 0x330c),\
+ PINGROUP(KB_COL5, PQ5, SYS, KBC, INVALID, TRACE, RSVD, KBC, INPUT, 0x3310),\
+ PINGROUP(KB_COL6, PQ6, SYS, KBC, INVALID, TRACE, INVALID, KBC, INPUT, 0x3314),\
+ PINGROUP(KB_COL7, PQ7, SYS, KBC, INVALID, TRACE, INVALID, KBC, INPUT, 0x3318),\
+ PINGROUP(CLK_32K_OUT, PA0, SYS, BLINK, RSVD1, RSVD2, RSVD3, BLINK, INPUT, 0x331c),\
+ PINGROUP(SYS_CLK_REQ, PZ5, SYS, SYSCLK, RSVD1, RSVD2, RSVD3, SYSCLK, INPUT, 0x3320),\
PINGROUP(CORE_PWR_REQ, INVALID, SYS, RSVD, RSVD, RSVD, RSVD, RSVD, INPUT, 0x3324),\
PINGROUP(CPU_PWR_REQ, INVALID, SYS, RSVD, RSVD, RSVD, RSVD, RSVD, INPUT, 0x3328),\
PINGROUP(PWR_INT_N, INVALID, SYS, RSVD, RSVD, RSVD, RSVD, RSVD, INPUT, 0x332c),\
PINGROUP(CLK_32K_IN, INVALID, SYS, RSVD, RSVD, RSVD, RSVD, RSVD, INPUT, 0x3330),\
- PINGROUP(OWR, INVALID, SYS, OWR, RSVD, RSVD, RSVD, RSVD, INPUT, 0x3334),\
- PINGROUP(DAP1_FS, PN0, AUDIO, I2S0, HDA, GMI, SDMMC2, RSVD, INPUT, 0x3338),\
- PINGROUP(DAP1_DIN, PN1, AUDIO, I2S0, HDA, GMI, SDMMC2, RSVD, INPUT, 0x333c),\
- PINGROUP(DAP1_DOUT, PN2, AUDIO, I2S0, HDA, GMI, SDMMC2, RSVD, INPUT, 0x3340),\
- PINGROUP(DAP1_SCLK, PN3, AUDIO, I2S0, HDA, GMI, SDMMC2, RSVD, INPUT, 0x3344),\
- PINGROUP(CLK1_REQ, PEE2, AUDIO, DAP, HDA, RSVD2, RSVD3, RSVD, INPUT, 0x3348),\
- PINGROUP(CLK1_OUT, PW4, AUDIO, EXTPERIPH1, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x334c),\
+ PINGROUP(OWR, INVALID, SYS, OWR, RSVD, RSVD, RSVD, OWR, INPUT, 0x3334),\
+ PINGROUP(DAP1_FS, PN0, AUDIO, I2S0, HDA, GMI, SDMMC2, I2S0, INPUT, 0x3338),\
+ PINGROUP(DAP1_DIN, PN1, AUDIO, I2S0, HDA, GMI, SDMMC2, I2S0, INPUT, 0x333c),\
+ PINGROUP(DAP1_DOUT, PN2, AUDIO, I2S0, HDA, GMI, SDMMC2, I2S0, INPUT, 0x3340),\
+ PINGROUP(DAP1_SCLK, PN3, AUDIO, I2S0, HDA, GMI, SDMMC2, I2S0, INPUT, 0x3344),\
+ PINGROUP(CLK1_REQ, PEE2, AUDIO, DAP, HDA, RSVD2, RSVD3, DAP, INPUT, 0x3348),\
+ PINGROUP(CLK1_OUT, PW4, AUDIO, EXTPERIPH1, RSVD1, RSVD2, RSVD3, EXTPERIPH1, INPUT, 0x334c),\
PINGROUP(SPDIF_IN, PK6, AUDIO, SPDIF, HDA, INVALID, DAPSDMMC2, RSVD, INPUT, 0x3350),\
PINGROUP(SPDIF_OUT, PK5, AUDIO, SPDIF, RSVD1, INVALID, DAPSDMMC2, RSVD, INPUT, 0x3354),\
- PINGROUP(DAP2_FS, PA2, AUDIO, I2S1, HDA, RSVD2, GMI, RSVD, INPUT, 0x3358),\
- PINGROUP(DAP2_DIN, PA4, AUDIO, I2S1, HDA, RSVD2, GMI, RSVD, INPUT, 0x335c),\
- PINGROUP(DAP2_DOUT, PA5, AUDIO, I2S1, HDA, RSVD2, GMI, RSVD, INPUT, 0x3360),\
- PINGROUP(DAP2_SCLK, PA3, AUDIO, I2S1, HDA, RSVD2, GMI, RSVD, INPUT, 0x3364),\
- PINGROUP(SPI2_MOSI, PX0, AUDIO, SPI6, SPI2, INVALID, GMI, RSVD, INPUT, 0x3368),\
- PINGROUP(SPI2_MISO, PX1, AUDIO, SPI6, SPI2, INVALID, GMI, RSVD, INPUT, 0x336c),\
- PINGROUP(SPI2_CS0_N, PX3, AUDIO, SPI6, SPI2, INVALID, GMI, RSVD, INPUT, 0x3370),\
- PINGROUP(SPI2_SCK, PX2, AUDIO, SPI6, SPI2, INVALID, GMI, RSVD, INPUT, 0x3374),\
- PINGROUP(SPI1_MOSI, PX4, AUDIO, SPI2, SPI1, INVALID, GMI, RSVD, INPUT, 0x3378),\
- PINGROUP(SPI1_SCK, PX5, AUDIO, SPI2, SPI1, INVALID, GMI, RSVD, INPUT, 0x337c),\
- PINGROUP(SPI1_CS0_N, PX6, AUDIO, SPI2, SPI1, INVALID, GMI, RSVD, INPUT, 0x3380),\
+ PINGROUP(DAP2_FS, PA2, AUDIO, I2S1, HDA, RSVD2, GMI, I2S1, INPUT, 0x3358),\
+ PINGROUP(DAP2_DIN, PA4, AUDIO, I2S1, HDA, RSVD2, GMI, I2S1, INPUT, 0x335c),\
+ PINGROUP(DAP2_DOUT, PA5, AUDIO, I2S1, HDA, RSVD2, GMI, I2S1, INPUT, 0x3360),\
+ PINGROUP(DAP2_SCLK, PA3, AUDIO, I2S1, HDA, RSVD2, GMI, I2S1, INPUT, 0x3364),\
+ PINGROUP(SPI2_MOSI, PX0, AUDIO, SPI6, SPI2, INVALID, GMI, SPI6, INPUT, 0x3368),\
+ PINGROUP(SPI2_MISO, PX1, AUDIO, SPI6, SPI2, INVALID, GMI, SPI6, INPUT, 0x336c),\
+ PINGROUP(SPI2_CS0_N, PX3, AUDIO, SPI6, SPI2, INVALID, GMI, SPI6, INPUT, 0x3370),\
+ PINGROUP(SPI2_SCK, PX2, AUDIO, SPI6, SPI2, INVALID, GMI, SPI6, INPUT, 0x3374),\
+ PINGROUP(SPI1_MOSI, PX4, AUDIO, SPI2, SPI1, INVALID, GMI, GMI, INPUT, 0x3378),\
+ PINGROUP(SPI1_SCK, PX5, AUDIO, SPI2, SPI1, INVALID, GMI, GMI, INPUT, 0x337c),\
+ PINGROUP(SPI1_CS0_N, PX6, AUDIO, SPI2, SPI1, INVALID, GMI, GMI, INPUT, 0x3380),\
PINGROUP(SPI1_MISO, PX7, AUDIO, INVALID, SPI1, INVALID, RSVD3, RSVD, INPUT, 0x3384),\
PINGROUP(SPI2_CS1_N, PW2, AUDIO, INVALID, SPI2, INVALID, INVALID, RSVD, INPUT, 0x3388),\
PINGROUP(SPI2_CS2_N, PW3, AUDIO, INVALID, SPI2, INVALID, INVALID, RSVD, INPUT, 0x338c),\
- PINGROUP(SDMMC3_CLK, PA6, SDMMC3, UARTA, PWM2, SDMMC3, INVALID, RSVD, INPUT, 0x3390),\
- PINGROUP(SDMMC3_CMD, PA7, SDMMC3, UARTA, PWM3, SDMMC3, INVALID, RSVD, INPUT, 0x3394),\
- PINGROUP(SDMMC3_DAT0, PB7, SDMMC3, RSVD0, RSVD1, SDMMC3, INVALID, RSVD, INPUT, 0x3398),\
- PINGROUP(SDMMC3_DAT1, PB6, SDMMC3, RSVD0, RSVD1, SDMMC3, INVALID, RSVD, INPUT, 0x339c),\
- PINGROUP(SDMMC3_DAT2, PB5, SDMMC3, RSVD0, PWM1, SDMMC3, INVALID, RSVD, INPUT, 0x33a0),\
- PINGROUP(SDMMC3_DAT3, PB4, SDMMC3, RSVD0, PWM0, SDMMC3, INVALID, RSVD, INPUT, 0x33a4),\
- PINGROUP(SDMMC3_DAT4, PD1, SDMMC3, PWM1, INVALID, SDMMC3, INVALID, RSVD, INPUT, 0x33a8),\
- PINGROUP(SDMMC3_DAT5, PD0, SDMMC3, PWM0, INVALID, SDMMC3, INVALID, RSVD, INPUT, 0x33ac),\
- PINGROUP(SDMMC3_DAT6, PD3, SDMMC3, SPDIF, INVALID, SDMMC3, INVALID, RSVD, INPUT, 0x33b0),\
- PINGROUP(SDMMC3_DAT7, PD4, SDMMC3, SPDIF, INVALID, SDMMC3, INVALID, RSVD, INPUT, 0x33b4),\
- PINGROUP(PEX_L0_PRSNT_N, PDD0, PEXCTL, PCIE, HDA, RSVD2, RSVD3, RSVD, INPUT, 0x33b8),\
- PINGROUP(PEX_L0_RST_N, PDD1, PEXCTL, PCIE, HDA, RSVD2, RSVD3, RSVD, INPUT, 0x33bc),\
- PINGROUP(PEX_L0_CLKREQ_N, PDD2, PEXCTL, PCIE, HDA, RSVD2, RSVD3, RSVD, INPUT, 0x33c0),\
- PINGROUP(PEX_WAKE_N, PDD3, PEXCTL, PCIE, HDA, RSVD2, RSVD3, RSVD, INPUT, 0x33c4),\
- PINGROUP(PEX_L1_PRSNT_N, PDD4, PEXCTL, PCIE, HDA, RSVD2, RSVD3, RSVD, INPUT, 0x33c8),\
- PINGROUP(PEX_L1_RST_N, PDD5, PEXCTL, PCIE, HDA, RSVD2, RSVD3, RSVD, INPUT, 0x33cc),\
- PINGROUP(PEX_L1_CLKREQ_N, PDD6, PEXCTL, PCIE, HDA, RSVD2, RSVD3, RSVD, INPUT, 0x33d0),\
- PINGROUP(PEX_L2_PRSNT_N, PDD7, PEXCTL, PCIE, HDA, RSVD2, RSVD3, RSVD, INPUT, 0x33d4),\
- PINGROUP(PEX_L2_RST_N, PCC6, PEXCTL, PCIE, HDA, RSVD2, RSVD3, RSVD, INPUT, 0x33d8),\
- PINGROUP(PEX_L2_CLKREQ_N, PCC7, PEXCTL, PCIE, HDA, RSVD2, RSVD3, RSVD, INPUT, 0x33dc),\
+ PINGROUP(SDMMC3_CLK, PA6, SDMMC3, UARTA, PWM2, SDMMC3, SPI3, SDMMC3, INPUT, 0x3390),\
+ PINGROUP(SDMMC3_CMD, PA7, SDMMC3, UARTA, PWM3, SDMMC3, INVALID, SDMMC3, INPUT, 0x3394),\
+ PINGROUP(SDMMC3_DAT0, PB7, SDMMC3, RSVD0, RSVD1, SDMMC3, SPI3, SDMMC3, INPUT, 0x3398),\
+ PINGROUP(SDMMC3_DAT1, PB6, SDMMC3, RSVD0, RSVD1, SDMMC3, SPI3, SDMMC3, INPUT, 0x339c),\
+ PINGROUP(SDMMC3_DAT2, PB5, SDMMC3, RSVD0, PWM1, SDMMC3, SPI3, SDMMC3, INPUT, 0x33a0),\
+ PINGROUP(SDMMC3_DAT3, PB4, SDMMC3, RSVD0, PWM0, SDMMC3, INVALID, SDMMC3, INPUT, 0x33a4),\
+ PINGROUP(SDMMC3_DAT4, PD1, SDMMC3, PWM1, INVALID, SDMMC3, INVALID, SDMMC3, INPUT, 0x33a8),\
+ PINGROUP(SDMMC3_DAT5, PD0, SDMMC3, PWM0, INVALID, SDMMC3, INVALID, SDMMC3, INPUT, 0x33ac),\
+ PINGROUP(SDMMC3_DAT6, PD3, SDMMC3, SPDIF, INVALID, SDMMC3, INVALID, SDMMC3, INPUT, 0x33b0),\
+ PINGROUP(SDMMC3_DAT7, PD4, SDMMC3, SPDIF, INVALID, SDMMC3, INVALID, SDMMC3, INPUT, 0x33b4),\
+ PINGROUP(PEX_L0_PRSNT_N, PDD0, PEXCTL, PCIE, HDA, RSVD2, RSVD3, PCIE, INPUT, 0x33b8),\
+ PINGROUP(PEX_L0_RST_N, PDD1, PEXCTL, PCIE, HDA, RSVD2, RSVD3, PCIE, INPUT, 0x33bc),\
+ PINGROUP(PEX_L0_CLKREQ_N, PDD2, PEXCTL, PCIE, HDA, RSVD2, RSVD3, PCIE, INPUT, 0x33c0),\
+ PINGROUP(PEX_WAKE_N, PDD3, PEXCTL, PCIE, HDA, RSVD2, RSVD3, PCIE, INPUT, 0x33c4),\
+ PINGROUP(PEX_L1_PRSNT_N, PDD4, PEXCTL, PCIE, HDA, RSVD2, RSVD3, PCIE, INPUT, 0x33c8),\
+ PINGROUP(PEX_L1_RST_N, PDD5, PEXCTL, PCIE, HDA, RSVD2, RSVD3, PCIE, INPUT, 0x33cc),\
+ PINGROUP(PEX_L1_CLKREQ_N, PDD6, PEXCTL, PCIE, HDA, RSVD2, RSVD3, PCIE, INPUT, 0x33d0),\
+ PINGROUP(PEX_L2_PRSNT_N, PDD7, PEXCTL, PCIE, HDA, RSVD2, RSVD3, PCIE, INPUT, 0x33d4),\
+ PINGROUP(PEX_L2_RST_N, PCC6, PEXCTL, PCIE, HDA, RSVD2, RSVD3, PCIE, INPUT, 0x33d8),\
+ PINGROUP(PEX_L2_CLKREQ_N, PCC7, PEXCTL, PCIE, HDA, RSVD2, RSVD3, PCIE, INPUT, 0x33dc),\
PINGROUP(HDMI_CEC, PEE3, SYS, CEC, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x33e0),\
/* END OF LIST */
diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c
index ed6c01fe8544..d1178a820f39 100644
--- a/arch/arm/mach-tegra/platsmp.c
+++ b/arch/arm/mach-tegra/platsmp.c
@@ -290,7 +290,10 @@ void __init platform_smp_prepare_cpus(unsigned int max_cpus)
#if defined(CONFIG_HAVE_ARM_SCU)
{
- u32 scu_ctrl = __raw_readl(scu_base) | 1 << 3;
+ u32 scu_ctrl = __raw_readl(scu_base) |
+ 1 << 3 | /* Enable speculative line fill*/
+ 1 << 5 | /* Enable IC standby */
+ 1 << 6; /* Enable SCU standby */
if (!(scu_ctrl & 1))
__raw_writel(scu_ctrl, scu_base);
}
diff --git a/arch/arm/mach-tegra/pm-irq.c b/arch/arm/mach-tegra/pm-irq.c
index 57d21361ca14..4a3f3c31830c 100644
--- a/arch/arm/mach-tegra/pm-irq.c
+++ b/arch/arm/mach-tegra/pm-irq.c
@@ -29,6 +29,7 @@
#include <mach/iomap.h>
#include "pm-irq.h"
+#include "wakeups.h"
#define PMC_CTRL 0x0
#define PMC_CTRL_LATCH_WAKEUPS (1 << 5)
@@ -144,12 +145,15 @@ static inline void clear_pmc_sw_wake_status(void)
int tegra_pm_irq_set_wake(int irq, int enable)
{
- int wake = tegra_irq_to_wake(irq);
+ struct wake_mask_types wake_msk;
+ int flow_type = -1;
+ int err;
- if (wake == -EALREADY) {
+ err = tegra_irq_to_wake(irq, flow_type, &wake_msk);
+ if (err == -EALREADY) {
/* EALREADY means wakeup event already accounted for */
return 0;
- } else if (wake == -ENOTSUPP) {
+ } else if (err == -ENOTSUPP) {
/* ENOTSUPP means LP0 not supported with this wake source */
WARN(enable && warn_prevent_lp0, "irq %d prevents lp0\n", irq);
if (enable)
@@ -157,46 +161,43 @@ int tegra_pm_irq_set_wake(int irq, int enable)
else if (!WARN_ON(tegra_prevent_lp0 == 0))
tegra_prevent_lp0--;
return 0;
- } else if (wake < 0) {
+ } else if (err < 0) {
return -EINVAL;
}
- if (enable) {
- tegra_lp0_wake_enb |= 1ull << wake;
- pr_info("Enabling wake%d\n", wake);
- } else {
- tegra_lp0_wake_enb &= ~(1ull << wake);
- pr_info("Disabling wake%d\n", wake);
- }
+ if (enable)
+ tegra_lp0_wake_enb |= (wake_msk.wake_mask_hi |
+ wake_msk.wake_mask_lo | wake_msk.wake_mask_any);
+ else
+ tegra_lp0_wake_enb &= ~(wake_msk.wake_mask_hi |
+ wake_msk.wake_mask_lo | wake_msk.wake_mask_any);
return 0;
}
int tegra_pm_irq_set_wake_type(int irq, int flow_type)
{
- int wake = tegra_irq_to_wake(irq);
+ struct wake_mask_types wake_msk;
+ int err;
+
+ err = tegra_irq_to_wake(irq, flow_type, &wake_msk);
- if (wake < 0)
+ if (err < 0)
return 0;
- switch (flow_type) {
- case IRQF_TRIGGER_FALLING:
- case IRQF_TRIGGER_LOW:
- tegra_lp0_wake_level &= ~(1ull << wake);
- tegra_lp0_wake_level_any &= ~(1ull << wake);
- break;
- case IRQF_TRIGGER_HIGH:
- case IRQF_TRIGGER_RISING:
- tegra_lp0_wake_level |= (1ull << wake);
- tegra_lp0_wake_level_any &= ~(1ull << wake);
- break;
-
- case IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING:
- tegra_lp0_wake_level_any |= (1ull << wake);
- break;
- default:
- return -EINVAL;
- }
+ /* configure LOW/FALLING polarity wake sources for an irq */
+ tegra_lp0_wake_level &= ~wake_msk.wake_mask_lo;
+ tegra_lp0_wake_level_any &= ~wake_msk.wake_mask_lo;
+
+ /* configure HIGH/RISING polarity wake sources for an irq */
+ tegra_lp0_wake_level |= wake_msk.wake_mask_hi;
+ tegra_lp0_wake_level_any &= ~wake_msk.wake_mask_hi;
+
+ /*
+ * configure RISING and FALLING i.e. ANY polarity wake
+ * sources for an irq
+ */
+ tegra_lp0_wake_level_any |= wake_msk.wake_mask_any;
return 0;
}
diff --git a/arch/arm/mach-tegra/pm-irq.h b/arch/arm/mach-tegra/pm-irq.h
index 8e87b4bba246..639bfe9c4cc9 100644
--- a/arch/arm/mach-tegra/pm-irq.h
+++ b/arch/arm/mach-tegra/pm-irq.h
@@ -22,8 +22,6 @@
int tegra_pm_irq_set_wake(int irq, int enable);
int tegra_pm_irq_set_wake_type(int irq, int flow_type);
bool tegra_pm_irq_lp0_allowed(void);
-int tegra_irq_to_wake(int irq);
-int tegra_wake_to_irq(int wake);
#else
static inline int tegra_pm_irq_set_wake_type(int irq, int flow_type)
{
diff --git a/arch/arm/mach-tegra/pm.c b/arch/arm/mach-tegra/pm.c
index 72ae30a6a29a..7a08bc1aef24 100644
--- a/arch/arm/mach-tegra/pm.c
+++ b/arch/arm/mach-tegra/pm.c
@@ -140,6 +140,11 @@ struct suspend_context tegra_sctx;
#define PMC_CPUPWROFF_TIMER 0xcc
#define PMC_COREPWROFF_TIMER PMC_WAKE_DELAY
+#define PMC_PWRGATE_TOGGLE 0x30
+#define PWRGATE_TOGGLE_START (1 << 8)
+#define UN_PWRGATE_CPU \
+ (PWRGATE_TOGGLE_START | TEGRA_CPU_POWERGATE_ID(TEGRA_POWERGATE_CPU))
+
#ifdef CONFIG_TEGRA_CLUSTER_CONTROL
#define PMC_SCRATCH4_WAKE_CLUSTER_MASK (1<<31)
#endif
@@ -586,7 +591,6 @@ unsigned int tegra_idle_lp2_last(unsigned int sleep_time, unsigned int flags)
mode |= TEGRA_POWER_PWRREQ_OE;
mode &= ~TEGRA_POWER_EFFECT_LP0;
writel(mode, pmc + PMC_CTRL);
- mode |= flags;
tegra_cluster_switch_time(flags, tegra_cluster_switch_time_id_start);
@@ -598,7 +602,17 @@ unsigned int tegra_idle_lp2_last(unsigned int sleep_time, unsigned int flags)
trace_cpu_cluster(POWER_CPU_CLUSTER_START);
set_power_timers(pdata->cpu_timer, 0,
clk_get_rate_all_locked(tegra_pclk));
- tegra_cluster_switch_prolog(mode);
+ if (flags & TEGRA_POWER_CLUSTER_G) {
+ /*
+ * To reduce the vdd_cpu up latency when LP->G
+ * transition. Before the transition, enable
+ * the vdd_cpu rail.
+ */
+ if (is_lp_cluster())
+ writel(UN_PWRGATE_CPU,
+ pmc + PMC_PWRGATE_TOGGLE);
+ }
+ tegra_cluster_switch_prolog(flags);
} else {
set_power_timers(pdata->cpu_timer, pdata->cpu_off_timer,
clk_get_rate_all_locked(tegra_pclk));
@@ -608,7 +622,7 @@ unsigned int tegra_idle_lp2_last(unsigned int sleep_time, unsigned int flags)
tegra_lp2_set_trigger(sleep_time);
cpu_complex_pm_enter();
- suspend_cpu_complex(mode);
+ suspend_cpu_complex(flags);
tegra_cluster_switch_time(flags, tegra_cluster_switch_time_id_prolog);
flush_cache_all();
/*
@@ -625,7 +639,7 @@ unsigned int tegra_idle_lp2_last(unsigned int sleep_time, unsigned int flags)
tegra_init_cache(false);
tegra_cluster_switch_time(flags, tegra_cluster_switch_time_id_switch);
- restore_cpu_complex(mode);
+ restore_cpu_complex(flags);
cpu_complex_pm_exit();
remain = tegra_lp2_timer_remain();
@@ -633,7 +647,7 @@ unsigned int tegra_idle_lp2_last(unsigned int sleep_time, unsigned int flags)
tegra_lp2_set_trigger(0);
if (flags & TEGRA_POWER_CLUSTER_MASK) {
- tegra_cluster_switch_epilog(mode);
+ tegra_cluster_switch_epilog(flags);
trace_cpu_cluster(POWER_CPU_CLUSTER_DONE);
}
tegra_cluster_switch_time(flags, tegra_cluster_switch_time_id_epilog);
@@ -878,6 +892,8 @@ int tegra_suspend_dram(enum tegra_suspend_mode mode, unsigned int flags)
local_fiq_disable();
+ trace_cpu_suspend(CPU_SUSPEND_START);
+
cpu_pm_enter();
cpu_complex_pm_enter();
@@ -941,6 +957,8 @@ int tegra_suspend_dram(enum tegra_suspend_mode mode, unsigned int flags)
if (pdata && pdata->board_resume)
pdata->board_resume(mode, TEGRA_RESUME_AFTER_CPU);
+ trace_cpu_suspend(CPU_SUSPEND_DONE);
+
local_fiq_enable();
tegra_common_resume();
diff --git a/arch/arm/mach-tegra/powergate.c b/arch/arm/mach-tegra/powergate.c
index 27bc3fc67e48..4c0d8bec276e 100644
--- a/arch/arm/mach-tegra/powergate.c
+++ b/arch/arm/mach-tegra/powergate.c
@@ -19,6 +19,7 @@
*/
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/clk.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
@@ -493,6 +494,7 @@ bool tegra_powergate_is_powered(int id)
status = pmc_read(PWRGATE_STATUS) & (1 << id);
return !!status;
}
+EXPORT_SYMBOL(tegra_powergate_is_powered);
int tegra_powergate_remove_clamping(int id)
{
diff --git a/arch/arm/mach-tegra/sleep-t3.S b/arch/arm/mach-tegra/sleep-t3.S
index 4417da33de38..23e96c605b96 100644
--- a/arch/arm/mach-tegra/sleep-t3.S
+++ b/arch/arm/mach-tegra/sleep-t3.S
@@ -92,6 +92,7 @@
#define CLK_RESET_PLLP_OUTB 0xa8
#define PMC_PLLP_WB0_OVERRIDE 0xf8
+#define PMC_PLLM_WB0_OVERRIDE 0x1dc
#define CLK_RESET_CLK_SOURCE_MSELECT 0x3b4
@@ -517,10 +518,12 @@ tegra3_cpu_clk32k:
tst r0, #PMC_CTRL_SIDE_EFFECT_LP0
beq lp1_clocks_prepare
- /* enable PLLM via PMC in LP0 */
+ /* enable PLLM auto-restart via PMC in LP0; restore override settings */
ldr r0, [r4, #PMC_PLLP_WB0_OVERRIDE]
orr r0, r0, #((1 << 12) | (1 << 11))
str r0, [r4, #PMC_PLLP_WB0_OVERRIDE]
+ ldr r0, [r4, #PMC_SCRATCH2]
+ str r0, [r4, #PMC_PLLM_WB0_OVERRIDE]
mov pc, lr
/* start by jumping to clkm to safely disable PLLs, then jump
diff --git a/arch/arm/mach-tegra/sleep.h b/arch/arm/mach-tegra/sleep.h
index 2557c3f687a8..c57399985ecd 100644
--- a/arch/arm/mach-tegra/sleep.h
+++ b/arch/arm/mach-tegra/sleep.h
@@ -50,6 +50,8 @@
#define TEGRA_IRAM_CODE_AREA (TEGRA_IRAM_BASE + SZ_4K)
+/* PMC_SCRATCH2 is used for PLLM boot state if PLLM auto-restart is enabled */
+#define PMC_SCRATCH2 0x58
/* PMC_SCRATCH37-39 and 41 are used for tegra_pen_lock in Tegra2 idle */
#define PMC_SCRATCH37 0x130
#define PMC_SCRATCH38 0x134
@@ -209,8 +211,8 @@ void tegra_sleep_cpu_save(unsigned long v2p);
void tegra_resume(void);
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
-extern void tegra2_iram_start;
-extern void tegra2_iram_end;
+extern unsigned int tegra2_iram_start;
+extern unsigned int tegra2_iram_end;
int tegra2_cpu_is_resettable_soon(void);
void tegra2_cpu_reset(int cpu);
void tegra2_cpu_set_resettable_soon(void);
@@ -219,8 +221,8 @@ void tegra2_sleep_core(unsigned long v2p);
void tegra2_hotplug_shutdown(void);
void tegra2_sleep_wfi(unsigned long v2p);
#else
-extern void tegra3_iram_start;
-extern void tegra3_iram_end;
+extern unsigned int tegra3_iram_start;
+extern unsigned int tegra3_iram_end;
void tegra3_sleep_core(unsigned long v2p);
void tegra3_sleep_cpu_secondary(unsigned long v2p);
void tegra3_hotplug_shutdown(void);
diff --git a/arch/arm/mach-tegra/syncpt.c b/arch/arm/mach-tegra/syncpt.c
deleted file mode 100644
index 8ebab3801a8a..000000000000
--- a/arch/arm/mach-tegra/syncpt.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2010 Google, Inc.
- *
- * Author:
- * Erik Gilling <konkers@google.com>
- *
- * Copyright (C) 2010, 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/init.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-
-#include <asm/mach/irq.h>
-
-#include <mach/iomap.h>
-#include <mach/irqs.h>
-
-#define HOST1X_SYNC_OFFSET 0x3000
-#define HOST1X_SYNC_SIZE 0x800
-enum {
- HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS = 0x40,
- HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE = 0x60
-};
-
-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)
-{
- void __iomem *sync_regs = irq_desc_get_handler_data(desc);
- unsigned long reg;
- int id;
- struct irq_chip *chip = irq_desc_get_chip(desc);
-
- chained_irq_enter(chip, desc);
-
- reg = readl(sync_regs + HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS);
-
- for_each_set_bit(id, &reg, 32)
- generic_handle_irq(id + INT_SYNCPT_THRESH_BASE);
-
- 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 int __init syncpt_init_irq(void)
-{
- void __iomem *sync_regs;
- unsigned int i;
- int irq;
-
- sync_regs = ioremap(TEGRA_HOST1X_BASE + HOST1X_SYNC_OFFSET,
- HOST1X_SYNC_SIZE);
- BUG_ON(!sync_regs);
-
- writel(0xffffffffUL,
- sync_regs + HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE);
- writel(0xffffffffUL,
- sync_regs + HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS);
-
- for (i = 0; i < INT_SYNCPT_THRESH_NR; i++) {
- irq = INT_SYNCPT_THRESH_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, sync_regs);
-
- return 0;
-}
-
-core_initcall(syncpt_init_irq);
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index 7c42e7b1481a..b1f1dd3f63c6 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -779,8 +779,9 @@ static int tegra2_pll_clk_set_rate(struct clk *c, unsigned long rate)
if (sel->input_rate == 0) {
unsigned long cfreq;
- BUG_ON(c->flags & PLLU);
struct clk_pll_freq_table cfg;
+
+ BUG_ON(c->flags & PLLU);
sel = &cfg;
switch (input_rate) {
@@ -2486,10 +2487,12 @@ struct clk tegra_list_periph_clks[] = {
PERIPH_CLK("tvdac", "tvdac", NULL, 53, 0x194, 0x31E, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */
PERIPH_CLK("disp1", "tegradc.0", NULL, 27, 0x138, 0x31E, 600000000, mux_pllp_plld_pllc_clkm, MUX), /* scales with voltage and process_id */
PERIPH_CLK("disp2", "tegradc.1", NULL, 26, 0x13c, 0x31E, 600000000, mux_pllp_plld_pllc_clkm, MUX), /* scales with voltage and process_id */
- PERIPH_CLK("usbd", "fsl-tegra-udc", NULL, 22, 0, 0x31E, 480000000, mux_clk_m, 0), /* requires min voltage */
+ PERIPH_CLK("usbd", "tegra-udc.0", NULL, 22, 0, 0x31E, 480000000, mux_clk_m, 0), /* requires min voltage */
PERIPH_CLK("usb2", "tegra-ehci.1", NULL, 58, 0, 0x31E, 480000000, mux_clk_m, 0), /* requires min voltage */
PERIPH_CLK("usb3", "tegra-ehci.2", NULL, 59, 0, 0x31E, 480000000, mux_clk_m, 0), /* requires min voltage */
PERIPH_CLK("dsia", "tegradc.0", "dsia", 48, 0, 0x31E, 500000000, mux_plld_out0, 0), /* scales with voltage */
+ PERIPH_CLK("dsi1-fixed", "tegradc.0", "dsi-fixed", 0, 0, 0x31E, 108000000, mux_pllp_out3, PERIPH_NO_ENB),
+ PERIPH_CLK("dsi2-fixed", "tegradc.1", "dsi-fixed", 0, 0, 0x31E, 108000000, mux_pllp_out3, PERIPH_NO_ENB),
PERIPH_CLK("csi", "tegra_camera", "csi", 52, 0, 0x31E, 72000000, mux_pllp_out3, 0),
PERIPH_CLK("isp", "tegra_camera", "isp", 23, 0, 0x31E, 150000000, mux_clk_m, 0), /* same frequency as VI */
PERIPH_CLK("csus", "tegra_camera", "csus", 92, 0, 0x31E, 150000000, mux_clk_m, PERIPH_NO_RESET),
@@ -2503,7 +2506,7 @@ struct clk tegra_list_shared_clks[] = {
SHARED_CLK("avp.sclk", "tegra-avp", "sclk", &tegra_clk_virtual_sclk),
SHARED_CLK("mon.sclk", "tegra-stat-mon", "sclk", &tegra_clk_virtual_sclk),
SHARED_CLK("bsea.sclk", "tegra-aes", "sclk", &tegra_clk_virtual_sclk),
- SHARED_CLK("usbd.sclk", "fsl-tegra-udc", "sclk", &tegra_clk_virtual_sclk),
+ SHARED_CLK("usbd.sclk", "tegra-udc.0", "sclk", &tegra_clk_virtual_sclk),
SHARED_CLK("usb1.sclk", "tegra-ehci.0", "sclk", &tegra_clk_virtual_sclk),
SHARED_CLK("usb2.sclk", "tegra-ehci.1", "sclk", &tegra_clk_virtual_sclk),
SHARED_CLK("usb3.sclk", "tegra-ehci.2", "sclk", &tegra_clk_virtual_sclk),
@@ -2519,7 +2522,7 @@ struct clk tegra_list_shared_clks[] = {
SHARED_CLK("3d.emc", "tegra_gr3d", "emc", &tegra_clk_emc),
SHARED_CLK("2d.emc", "tegra_gr2d", "emc", &tegra_clk_emc),
SHARED_CLK("mpe.emc", "tegra_mpe", "emc", &tegra_clk_emc),
- SHARED_CLK("usbd.emc", "fsl-tegra-udc", "emc", &tegra_clk_emc),
+ SHARED_CLK("usbd.emc", "tegra-udc.0", "emc", &tegra_clk_emc),
SHARED_CLK("usb1.emc", "tegra-ehci.0", "emc", &tegra_clk_emc),
SHARED_CLK("usb2.emc", "tegra-ehci.1", "emc", &tegra_clk_emc),
SHARED_CLK("usb3.emc", "tegra-ehci.2", "emc", &tegra_clk_emc),
@@ -2770,7 +2773,7 @@ unsigned long tegra_emc_to_cpu_ratio(unsigned long cpu_rate)
#ifdef CONFIG_PM_SLEEP
static u32 clk_rst_suspend[RST_DEVICES_NUM + CLK_OUT_ENB_NUM +
- PERIPH_CLK_SOURCE_NUM + 22];
+ PERIPH_CLK_SOURCE_NUM + 24];
static int tegra_clk_suspend(void)
{
@@ -2778,6 +2781,8 @@ static int tegra_clk_suspend(void)
u32 *ctx = clk_rst_suspend;
*ctx++ = clk_readl(OSC_CTRL) & OSC_CTRL_MASK;
+ *ctx++ = clk_readl(tegra_pll_p_out1.reg);
+ *ctx++ = clk_readl(tegra_pll_p_out3.reg);
*ctx++ = clk_readl(tegra_pll_c.reg + PLL_BASE);
*ctx++ = clk_readl(tegra_pll_c.reg + PLL_MISC(&tegra_pll_c));
*ctx++ = clk_readl(tegra_pll_a.reg + PLL_BASE);
@@ -2830,11 +2835,26 @@ static void tegra_clk_resume(void)
unsigned long off, i;
const u32 *ctx = clk_rst_suspend;
u32 val;
+ u32 pll_p_out12, pll_p_out34;
+ u32 pll_m_out1, pll_a_out0, pll_c_out1;
val = clk_readl(OSC_CTRL) & ~OSC_CTRL_MASK;
val |= *ctx++;
clk_writel(val, OSC_CTRL);
+ /* Since we are going to reset devices and switch clock sources in this
+ * function, plls and secondary dividers is required to be enabled. The
+ * actual value will be restored back later. Note that boot plls: pllm,
+ * pllp, and pllu are already configured and enabled.
+ */
+
+ val = PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE;
+ val |= val << 16;
+ pll_p_out12 = *ctx++;
+ clk_writel(pll_p_out12 | val, tegra_pll_p_out1.reg);
+ pll_p_out34 = *ctx++;
+ clk_writel(pll_p_out34 | val, tegra_pll_p_out3.reg);
+
clk_writel(*ctx++, tegra_pll_c.reg + PLL_BASE);
clk_writel(*ctx++, tegra_pll_c.reg + PLL_MISC(&tegra_pll_c));
clk_writel(*ctx++, tegra_pll_a.reg + PLL_BASE);
@@ -2847,9 +2867,13 @@ static void tegra_clk_resume(void)
clk_writel(*ctx++, tegra_pll_u.reg + PLL_MISC(&tegra_pll_u));
udelay(1000);
- clk_writel(*ctx++, tegra_pll_m_out1.reg);
- clk_writel(*ctx++, tegra_pll_a_out0.reg);
- clk_writel(*ctx++, tegra_pll_c_out1.reg);
+ val = PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE;
+ pll_m_out1 = *ctx++;
+ clk_writel(pll_m_out1 | val, tegra_pll_m_out1.reg);
+ pll_a_out0 = *ctx++;
+ clk_writel(pll_a_out0 | val, tegra_pll_a_out0.reg);
+ pll_c_out1 = *ctx++;
+ clk_writel(pll_c_out1 | val, tegra_pll_c_out1.reg);
clk_writel(*ctx++, tegra_clk_cclk.reg);
clk_writel(*ctx++, tegra_clk_cclk.reg + SUPER_CLK_DIVIDER);
@@ -2886,6 +2910,13 @@ static void tegra_clk_resume(void)
clk_writel(*ctx++, MISC_CLK_ENB);
clk_writel(*ctx++, CLK_MASK_ARM);
+
+ /* Restore back the actual pll and secondary divider values */
+ clk_writel(pll_p_out12, tegra_pll_p_out1.reg);
+ clk_writel(pll_p_out34, tegra_pll_p_out3.reg);
+ clk_writel(pll_m_out1, tegra_pll_m_out1.reg);
+ clk_writel(pll_a_out0, tegra_pll_a_out0.reg);
+ clk_writel(pll_c_out1, tegra_pll_c_out1.reg);
}
#else
diff --git a/arch/arm/mach-tegra/tegra2_host1x_devices.h b/arch/arm/mach-tegra/tegra2_host1x_devices.h
new file mode 100644
index 000000000000..974154a414dd
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra2_host1x_devices.h
@@ -0,0 +1,26 @@
+/*
+ * drivers/video/tegra/host/tegra2_host1x_devices.h
+ *
+ * Tegra2 Graphics Host Devices
+ *
+ * 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 TEGRA2_HOST1X_DEVICES_H
+#define TEGRA2_HOST1X_DEVICES_H
+
+int tegra2_register_host1x_devices(void);
+
+#endif
diff --git a/arch/arm/mach-tegra/tegra2_mc.c b/arch/arm/mach-tegra/tegra2_mc.c
index 6df9c232c02f..f25a1790a087 100644
--- a/arch/arm/mach-tegra/tegra2_mc.c
+++ b/arch/arm/mach-tegra/tegra2_mc.c
@@ -281,7 +281,8 @@ static int tegra_mc_client_parse(const char *buf, size_t count,
};
int ret = 0, i, token, index = 0;
bool aggregate = false;
- int period, *client_ids, mode;
+ int period, *client_ids;
+ int mode = FILTER_NONE;
u64 address_low = 0;
u64 address_length = 1ull << 32;
@@ -896,8 +897,10 @@ static enum hrtimer_restart sample_timer_function(struct hrtimer *handle)
#define REGISTER_SYSFS(_name, _val) \
tegra_mc_dram_##_name##_kobj = \
kobject_create_and_add(#_name, tegra_mc_dram_kobj); \
- sysfs_create_group(tegra_mc_dram_##_name##_kobj, \
- &tegra_mc_dram_##_name##_attr_group);
+ if (sysfs_create_group(tegra_mc_dram_##_name##_kobj, \
+ &tegra_mc_dram_##_name##_attr_group)) \
+ printk(KERN_ERR "\n sysfs_create_group failed at %s" \
+ " line %d\n", __FILE__, __LINE__);
static int tegra_mc_init(void)
{
diff --git a/arch/arm/mach-tegra/tegra2_usb_phy.c b/arch/arm/mach-tegra/tegra2_usb_phy.c
new file mode 100644
index 000000000000..6e0801625614
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra2_usb_phy.c
@@ -0,0 +1,1938 @@
+/*
+ * arch/arm/mach-tegra/tegra2_usb_phy.c
+ *
+ * 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
+ * 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/resource.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/ulpi.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/platform_data/tegra_usb.h>
+#include <mach/clk.h>
+#include <mach/iomap.h>
+#include <mach/pinmux.h>
+#include <asm/mach-types.h>
+#include <mach/usb_phy.h>
+#include "tegra_usb_phy.h"
+#include "gpio-names.h"
+#include "fuse.h"
+
+
+#define USB_USBCMD 0x140
+#define USB_USBCMD_RS (1 << 0)
+#define USB_USBCMD_RESET (1 << 1)
+
+#define USB_USBSTS 0x144
+#define USB_USBSTS_PCI (1 << 2)
+#define USB_USBSTS_SRI (1 << 7)
+#define USB_USBSTS_HCH (1 << 12)
+
+#define USB_ASYNCLISTADDR 0x158
+
+#define USB_TXFILLTUNING 0x164
+#define USB_FIFO_TXFILL_THRES(x) (((x) & 0x1f) << 16)
+#define USB_FIFO_TXFILL_MASK 0x1f0000
+
+#define ULPI_VIEWPORT 0x170
+#define ULPI_WAKEUP (1 << 31)
+#define ULPI_RUN (1 << 30)
+#define ULPI_RD_WR (1 << 29)
+
+#define USB_PORTSC 0x184
+#define USB_PORTSC_PTS(x) (((x) & 0x3) << 30)
+#define USB_PORTSC_PSPD(x) (((x) & 0x3) << 26)
+#define USB_PORTSC_PHCD (1 << 23)
+#define USB_PORTSC_WKOC (1 << 22)
+#define USB_PORTSC_WKDS (1 << 21)
+#define USB_PORTSC_WKCN (1 << 20)
+#define USB_PORTSC_PTC(x) (((x) & 0xf) << 16)
+#define USB_PORTSC_PP (1 << 12)
+#define USB_PORTSC_LS(x) (((x) & 0x3) << 10)
+#define USB_PORTSC_SUSP (1 << 7)
+#define USB_PORTSC_OCC (1 << 5)
+#define USB_PORTSC_PEC (1 << 3)
+#define USB_PORTSC_PE (1 << 2)
+#define USB_PORTSC_CSC (1 << 1)
+#define USB_PORTSC_CCS (1 << 0)
+#define USB_PORTSC_RWC_BITS (USB_PORTSC_CSC | USB_PORTSC_PEC | USB_PORTSC_OCC)
+#define USB_PORTSC_PSPD_MASK 3
+
+#define USB_USBMODE_REG_OFFSET 0x1a8
+#define USB_USBMODE_MASK (3 << 0)
+#define USB_USBMODE_HOST (3 << 0)
+#define USB_USBMODE_DEVICE (2 << 0)
+
+#define USB_SUSP_CTRL 0x400
+#define USB_WAKE_ON_CNNT_EN_DEV (1 << 3)
+#define USB_WAKE_ON_DISCON_EN_DEV (1 << 4)
+#define USB_SUSP_CLR (1 << 5)
+#define USB_CLKEN (1 << 6)
+#define USB_PHY_CLK_VALID (1 << 7)
+#define USB_PHY_CLK_VALID_INT_ENB (1 << 9)
+#define UTMIP_RESET (1 << 11)
+#define UHSIC_RESET (1 << 11)
+#define UTMIP_PHY_ENABLE (1 << 12)
+#define UHSIC_PHY_ENABLE (1 << 12)
+#define ULPI_PHY_ENABLE (1 << 13)
+#define USB_SUSP_SET (1 << 14)
+#define USB_WAKEUP_DEBOUNCE_COUNT(x) (((x) & 0x7) << 16)
+#define USB_PHY_CLK_VALID_INT_STS (1 << 8)
+
+#define USB_PHY_VBUS_WAKEUP_ID 0x408
+#define VDAT_DET_INT_EN (1 << 16)
+#define VDAT_DET_CHG_DET (1 << 17)
+#define VDAT_DET_STS (1 << 18)
+#define USB_ID_STATUS (1 << 2)
+
+#define USB1_LEGACY_CTRL 0x410
+#define USB1_NO_LEGACY_MODE (1 << 0)
+#define USB1_VBUS_SENSE_CTL_MASK (3 << 1)
+#define USB1_VBUS_SENSE_CTL_VBUS_WAKEUP (0 << 1)
+#define USB1_VBUS_SENSE_CTL_AB_SESS_VLD_OR_VBUS_WAKEUP \
+ (1 << 1)
+#define USB1_VBUS_SENSE_CTL_AB_SESS_VLD (2 << 1)
+#define USB1_VBUS_SENSE_CTL_A_SESS_VLD (3 << 1)
+
+#define ULPIS2S_CTRL 0x418
+#define ULPIS2S_ENA (1 << 0)
+#define ULPIS2S_SUPPORT_DISCONNECT (1 << 2)
+#define ULPIS2S_PLLU_MASTER_BLASTER60 (1 << 3)
+#define ULPIS2S_SPARE(x) (((x) & 0xF) << 8)
+#define ULPIS2S_FORCE_ULPI_CLK_OUT (1 << 12)
+#define ULPIS2S_DISCON_DONT_CHECK_SE0 (1 << 13)
+#define ULPIS2S_SUPPORT_HS_KEEP_ALIVE (1 << 14)
+#define ULPIS2S_DISABLE_STP_PU (1 << 15)
+#define ULPIS2S_SLV0_CLAMP_XMIT (1 << 16)
+
+#define ULPI_TIMING_CTRL_0 0x424
+#define ULPI_CLOCK_OUT_DELAY(x) ((x) & 0x1F)
+#define ULPI_OUTPUT_PINMUX_BYP (1 << 10)
+#define ULPI_CLKOUT_PINMUX_BYP (1 << 11)
+#define ULPI_SHADOW_CLK_LOOPBACK_EN (1 << 12)
+#define ULPI_SHADOW_CLK_SEL (1 << 13)
+#define ULPI_CORE_CLK_SEL (1 << 14)
+#define ULPI_SHADOW_CLK_DELAY(x) (((x) & 0x1F) << 16)
+#define ULPI_LBK_PAD_EN (1 << 26)
+#define ULPI_LBK_PAD_E_INPUT_OR (1 << 27)
+#define ULPI_CLK_OUT_ENA (1 << 28)
+#define ULPI_CLK_PADOUT_ENA (1 << 29)
+
+#define ULPI_TIMING_CTRL_1 0x428
+#define ULPI_DATA_TRIMMER_LOAD (1 << 0)
+#define ULPI_DATA_TRIMMER_SEL(x) (((x) & 0x7) << 1)
+#define ULPI_STPDIRNXT_TRIMMER_LOAD (1 << 16)
+#define ULPI_STPDIRNXT_TRIMMER_SEL(x) (((x) & 0x7) << 17)
+#define ULPI_DIR_TRIMMER_LOAD (1 << 24)
+#define ULPI_DIR_TRIMMER_SEL(x) (((x) & 0x7) << 25)
+
+#define UTMIP_PLL_CFG1 0x804
+#define UHSIC_PLL_CFG1 0x804
+#define UTMIP_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0)
+#define UTMIP_PLLU_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 27)
+#define UHSIC_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0)
+#define UHSIC_PLLU_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 14)
+
+#define UTMIP_XCVR_UHSIC_HSRX_CFG0 0x808
+#define UTMIP_XCVR_SETUP(x) (((x) & 0xf) << 0)
+#define UHSIC_ELASTIC_UNDERRUN_LIMIT(x) (((x) & 0x1f) << 2)
+#define UHSIC_ELASTIC_OVERRUN_LIMIT(x) (((x) & 0x1f) << 8)
+#define UTMIP_XCVR_LSRSLEW(x) (((x) & 0x3) << 8)
+#define UTMIP_XCVR_LSFSLEW(x) (((x) & 0x3) << 10)
+#define UHSIC_IDLE_WAIT(x) (((x) & 0x1f) << 13)
+#define UTMIP_FORCE_PD_POWERDOWN (1 << 14)
+#define UTMIP_FORCE_PD2_POWERDOWN (1 << 16)
+#define UTMIP_FORCE_PDZI_POWERDOWN (1 << 18)
+#define UTMIP_XCVR_LSBIAS_SEL (1 << 21)
+#define UTMIP_XCVR_SETUP_MSB(x) (((x) & 0x7) << 22)
+#define UTMIP_XCVR_HSSLEW_MSB(x) (((x) & 0x7f) << 25)
+#define UTMIP_XCVR_MAX_OFFSET 2
+#define UTMIP_XCVR_SETUP_MAX_VALUE 0x7f
+#define UTMIP_XCVR_SETUP_MIN_VALUE 0
+#define XCVR_SETUP_MSB_CALIB(x) ((x) >> 4)
+
+#define UTMIP_BIAS_CFG0 0x80c
+#define UTMIP_OTGPD (1 << 11)
+#define UTMIP_BIASPD (1 << 10)
+
+#define UHSIC_HSRX_CFG1 0x80c
+#define UHSIC_HS_SYNC_START_DLY(x) (((x) & 0x1f) << 1)
+
+#define UTMIP_HSRX_CFG0 0x810
+#define UTMIP_ELASTIC_LIMIT(x) (((x) & 0x1f) << 10)
+#define UTMIP_IDLE_WAIT(x) (((x) & 0x1f) << 15)
+
+#define UTMIP_HSRX_CFG1 0x814
+#define UHSIC_MISC_CFG0 0x814
+#define UTMIP_HS_SYNC_START_DLY(x) (((x) & 0x1f) << 1)
+#define UHSIC_SUSPEND_EXIT_ON_EDGE (1 << 7)
+#define UHSIC_DETECT_SHORT_CONNECT (1 << 8)
+#define UHSIC_FORCE_XCVR_MODE (1 << 15)
+
+#define UHSIC_MISC_CFG1 0x818
+#define UHSIC_PLLU_STABLE_COUNT(x) (((x) & 0xfff) << 2)
+
+#define UHSIC_PADS_CFG0 0x81c
+#define UHSIC_TX_RTUNEN 0xf000
+#define UHSIC_TX_RTUNE(x) (((x) & 0xf) << 12)
+
+#define UTMIP_TX_CFG0 0x820
+#define UHSIC_PADS_CFG1 0x820
+#define UHSIC_PD_BG (1 << 2)
+#define UHSIC_PD_TX (1 << 3)
+#define UHSIC_PD_TRK (1 << 4)
+#define UHSIC_PD_RX (1 << 5)
+#define UHSIC_PD_ZI (1 << 6)
+#define UHSIC_RX_SEL (1 << 7)
+#define UHSIC_RPD_DATA (1 << 9)
+#define UHSIC_RPD_STROBE (1 << 10)
+#define UHSIC_RPU_DATA (1 << 11)
+#define UHSIC_RPU_STROBE (1 << 12)
+#define UTMIP_FS_PREABMLE_J (1 << 19)
+#define UTMIP_HS_DISCON_DISABLE (1 << 8)
+
+#define UTMIP_MISC_CFG0 0x824
+#define UTMIP_DPDM_OBSERVE (1 << 26)
+#define UTMIP_DPDM_OBSERVE_SEL(x) (((x) & 0xf) << 27)
+#define UTMIP_DPDM_OBSERVE_SEL_FS_J UTMIP_DPDM_OBSERVE_SEL(0xf)
+#define UTMIP_DPDM_OBSERVE_SEL_FS_K UTMIP_DPDM_OBSERVE_SEL(0xe)
+#define UTMIP_DPDM_OBSERVE_SEL_FS_SE1 UTMIP_DPDM_OBSERVE_SEL(0xd)
+#define UTMIP_DPDM_OBSERVE_SEL_FS_SE0 UTMIP_DPDM_OBSERVE_SEL(0xc)
+#define UTMIP_SUSPEND_EXIT_ON_EDGE (1 << 22)
+#define FORCE_PULLDN_DM (1 << 8)
+#define FORCE_PULLDN_DP (1 << 9)
+#define COMB_TERMS (1 << 0)
+#define ALWAYS_FREE_RUNNING_TERMS (1 << 1)
+
+#define USB1_PREFETCH_ID 6
+#define USB2_PREFETCH_ID 18
+#define USB3_PREFETCH_ID 17
+
+#define UTMIP_MISC_CFG1 0x828
+#define UTMIP_PLL_ACTIVE_DLY_COUNT(x) (((x) & 0x1f) << 18)
+#define UTMIP_PLLU_STABLE_COUNT(x) (((x) & 0xfff) << 6)
+
+#define UHSIC_STAT_CFG0 0x828
+#define UHSIC_CONNECT_DETECT (1 << 0)
+
+#define UTMIP_DEBOUNCE_CFG0 0x82c
+#define UTMIP_BIAS_DEBOUNCE_A(x) (((x) & 0xffff) << 0)
+
+#define UTMIP_BAT_CHRG_CFG0 0x830
+#define UTMIP_PD_CHRG (1 << 0)
+#define UTMIP_ON_SINK_EN (1 << 2)
+#define UTMIP_OP_SRC_EN (1 << 3)
+
+#define UTMIP_SPARE_CFG0 0x834
+#define FUSE_SETUP_SEL (1 << 3)
+#define FUSE_ATERM_SEL (1 << 4)
+
+#define UTMIP_XCVR_CFG1 0x838
+#define UTMIP_FORCE_PDDISC_POWERDOWN (1 << 0)
+#define UTMIP_FORCE_PDCHRP_POWERDOWN (1 << 2)
+#define UTMIP_FORCE_PDDR_POWERDOWN (1 << 4)
+#define UTMIP_XCVR_TERM_RANGE_ADJ(x) (((x) & 0xf) << 18)
+
+#define UTMIP_BIAS_CFG1 0x83c
+#define UTMIP_BIAS_PDTRK_COUNT(x) (((x) & 0x1f) << 3)
+
+#define FUSE_USB_CALIB_0 0x1F0
+#define FUSE_USB_CALIB_XCVR_SETUP(x) (((x) & 0x7F) << 0)
+
+#define APB_MISC_GP_OBSCTRL_0 0x818
+#define APB_MISC_GP_OBSDATA_0 0x81c
+
+/* ULPI GPIO */
+#define ULPI_STP TEGRA_GPIO_PY3
+#define ULPI_DIR TEGRA_GPIO_PY1
+#define ULPI_D0 TEGRA_GPIO_PO1
+#define ULPI_D1 TEGRA_GPIO_PO2
+
+/* These values (in milli second) are taken from the battery charging spec */
+#define TDP_SRC_ON_MS 100
+#define TDPSRC_CON_MS 40
+
+#ifdef DEBUG
+#define DBG(stuff...) pr_info("tegra2_usb_phy: " stuff)
+#else
+#define DBG(stuff...) do {} while (0)
+#endif
+
+
+static DEFINE_SPINLOCK(utmip_pad_lock);
+static int utmip_pad_count;
+static int utmip_pad_state_on;
+
+static struct tegra_xtal_freq utmip_freq_table[] = {
+ {
+ .freq = 12000000,
+ .enable_delay = 0x02,
+ .stable_count = 0x2F,
+ .active_delay = 0x04,
+ .xtal_freq_count = 0x76,
+ .debounce = 0x7530,
+ .pdtrk_count = 5,
+ },
+ {
+ .freq = 13000000,
+ .enable_delay = 0x02,
+ .stable_count = 0x33,
+ .active_delay = 0x05,
+ .xtal_freq_count = 0x7F,
+ .debounce = 0x7EF4,
+ .pdtrk_count = 5,
+ },
+ {
+ .freq = 19200000,
+ .enable_delay = 0x03,
+ .stable_count = 0x4B,
+ .active_delay = 0x06,
+ .xtal_freq_count = 0xBB,
+ .debounce = 0xBB80,
+ .pdtrk_count = 7,
+ },
+ {
+ .freq = 26000000,
+ .enable_delay = 0x04,
+ .stable_count = 0x66,
+ .active_delay = 0x09,
+ .xtal_freq_count = 0xFE,
+ .debounce = 0xFDE8,
+ .pdtrk_count = 9,
+ },
+};
+
+static struct tegra_xtal_freq uhsic_freq_table[] = {
+ {
+ .freq = 12000000,
+ .enable_delay = 0x02,
+ .stable_count = 0x2F,
+ .active_delay = 0x0,
+ .xtal_freq_count = 0x1CA,
+ },
+ {
+ .freq = 13000000,
+ .enable_delay = 0x02,
+ .stable_count = 0x33,
+ .active_delay = 0x0,
+ .xtal_freq_count = 0x1F0,
+ },
+ {
+ .freq = 19200000,
+ .enable_delay = 0x03,
+ .stable_count = 0x4B,
+ .active_delay = 0x0,
+ .xtal_freq_count = 0x2DD,
+ },
+ {
+ .freq = 26000000,
+ .enable_delay = 0x04,
+ .stable_count = 0x66,
+ .active_delay = 0x0,
+ .xtal_freq_count = 0x3E0,
+ },
+};
+
+static void usb_phy_fence_read(struct tegra_usb_phy *phy)
+{
+ /* Fence read for coherency of AHB master intiated writes */
+ if (phy->inst == 0)
+ readb(IO_ADDRESS(IO_PPCS_PHYS + USB1_PREFETCH_ID));
+ else if (phy->inst == 1)
+ readb(IO_ADDRESS(IO_PPCS_PHYS + USB2_PREFETCH_ID));
+ else if (phy->inst == 2)
+ readb(IO_ADDRESS(IO_PPCS_PHYS + USB3_PREFETCH_ID));
+
+ return;
+}
+
+static int usb_phy_bringup_host_controller(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ DBG("USB_USBSTS[0x%x] USB_PORTSC[0x%x] port_speed[%d] - 0\n",
+ readl(base + USB_USBSTS), readl(base + USB_PORTSC),
+ phy->port_speed);
+
+ /* enable host mode */
+ val = readl(base + USB_USBMODE_REG_OFFSET);
+ val |= USB_USBMODE_HOST;
+ writel(val, base + USB_USBMODE_REG_OFFSET);
+
+ /* Enable Port Power */
+ val = readl(base + USB_PORTSC);
+ val |= USB_PORTSC_PP;
+ writel(val, base + USB_PORTSC);
+ udelay(10);
+
+ /* Check if the phy resume from LP0. When the phy resume from LP0
+ * USB register will be reset.to zero */
+ if (!readl(base + USB_ASYNCLISTADDR)) {
+ val = readl(base + USB_USBCMD);
+ val |= USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+
+ /* Program the field PTC based on the saved speed mode */
+ val = readl(base + USB_PORTSC);
+ val &= ~(USB_PORTSC_PTC(~0));
+ if (phy->port_speed == USB_PHY_PORT_SPEED_HIGH)
+ val |= USB_PORTSC_PTC(5);
+ else if (phy->port_speed == USB_PHY_PORT_SPEED_FULL)
+ val |= USB_PORTSC_PTC(6);
+ else if (phy->port_speed == USB_PHY_PORT_SPEED_LOW)
+ val |= USB_PORTSC_PTC(7);
+ writel(val, base + USB_PORTSC);
+ udelay(10);
+
+ /* Disable test mode by setting PTC field to NORMAL_OP */
+ val = readl(base + USB_PORTSC);
+ val &= ~(USB_PORTSC_PTC(~0));
+ writel(val, base + USB_PORTSC);
+ udelay(10);
+ }
+
+ /* Poll until CCS is enabled */
+ if (usb_phy_reg_status_wait(base + USB_PORTSC, USB_PORTSC_CCS,
+ USB_PORTSC_CCS, 2000)) {
+ pr_err("%s: timeout waiting for USB_PORTSC_CCS\n", __func__);
+ }
+
+ /* Poll until PE is enabled */
+ if (usb_phy_reg_status_wait(base + USB_PORTSC, USB_PORTSC_PE,
+ USB_PORTSC_PE, 2000)) {
+ pr_err("%s: timeout waiting for USB_PORTSC_PE\n", __func__);
+ }
+
+ /* Clear the PCI status, to avoid an interrupt taken upon resume */
+ val = readl(base + USB_USBSTS);
+ val |= USB_USBSTS_PCI;
+ writel(val, base + USB_USBSTS);
+
+ /* Put controller in suspend mode by writing 1 to SUSP bit of PORTSC */
+ val = readl(base + USB_PORTSC);
+ if ((val & USB_PORTSC_PP) && (val & USB_PORTSC_PE)) {
+ val |= USB_PORTSC_SUSP;
+ writel(val, base + USB_PORTSC);
+ /* Need a 4ms delay before the controller goes to suspend */
+ mdelay(4);
+
+ /* Wait until port suspend completes */
+ if (usb_phy_reg_status_wait(base + USB_PORTSC, USB_PORTSC_SUSP,
+ USB_PORTSC_SUSP, 1000)) {
+ pr_err("%s: timeout waiting for PORT_SUSPEND\n",
+ __func__);
+ }
+ }
+
+ DBG("USB_USBSTS[0x%x] USB_PORTSC[0x%x]\n",
+ readl(base + USB_USBSTS), readl(base + USB_PORTSC));
+
+ return 0;
+}
+
+static void usb_phy_wait_for_sof(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ val = readl(base + USB_USBSTS);
+ writel(val, base + USB_USBSTS);
+ udelay(20);
+ /* wait for two SOFs */
+ if (usb_phy_reg_status_wait(base + USB_USBSTS, USB_USBSTS_SRI,
+ USB_USBSTS_SRI, 2500))
+ pr_err("%s: timeout waiting for SOF\n", __func__);
+
+ val = readl(base + USB_USBSTS);
+ writel(val, base + USB_USBSTS);
+ if (usb_phy_reg_status_wait(base + USB_USBSTS, USB_USBSTS_SRI, 0, 2500))
+ pr_err("%s: timeout waiting for SOF\n", __func__);
+
+ if (usb_phy_reg_status_wait(base + USB_USBSTS, USB_USBSTS_SRI,
+ USB_USBSTS_SRI, 2500))
+ pr_err("%s: timeout waiting for SOF\n", __func__);
+
+ udelay(20);
+}
+
+static unsigned int utmi_phy_xcvr_setup_value(struct tegra_usb_phy *phy)
+{
+ struct tegra_utmi_config *cfg = &phy->pdata->u_cfg.utmi;
+ signed long val;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (cfg->xcvr_use_fuses) {
+ val = FUSE_USB_CALIB_XCVR_SETUP(
+ tegra_fuse_readl(FUSE_USB_CALIB_0));
+ if (cfg->xcvr_setup_offset <= UTMIP_XCVR_MAX_OFFSET)
+ val = val + cfg->xcvr_setup_offset;
+
+ if (val > UTMIP_XCVR_SETUP_MAX_VALUE) {
+ val = UTMIP_XCVR_SETUP_MAX_VALUE;
+ pr_info("%s: reset XCVR_SETUP to max value\n",
+ __func__);
+ } else if (val < UTMIP_XCVR_SETUP_MIN_VALUE) {
+ val = UTMIP_XCVR_SETUP_MIN_VALUE;
+ pr_info("%s: reset XCVR_SETUP to min value\n",
+ __func__);
+ }
+ } else {
+ val = cfg->xcvr_setup;
+ }
+
+ return (unsigned int) val;
+}
+
+
+static int utmi_phy_open(struct tegra_usb_phy *phy)
+{
+ unsigned long parent_rate;
+ int i;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ phy->utmi_pad_clk = clk_get_sys("utmip-pad", NULL);
+ if (IS_ERR(phy->utmi_pad_clk)) {
+ pr_err("%s: can't get utmip pad clock\n", __func__);
+ return PTR_ERR(phy->utmi_pad_clk);
+ }
+
+ phy->utmi_xcvr_setup = utmi_phy_xcvr_setup_value(phy);
+
+ parent_rate = clk_get_rate(clk_get_parent(phy->pllu_clk));
+ for (i = 0; i < ARRAY_SIZE(utmip_freq_table); i++) {
+ if (utmip_freq_table[i].freq == parent_rate) {
+ phy->freq = &utmip_freq_table[i];
+ break;
+ }
+ }
+ if (!phy->freq) {
+ pr_err("invalid pll_u parent rate %ld\n", parent_rate);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void utmi_phy_close(struct tegra_usb_phy *phy)
+{
+ DBG("%s inst:[%d]\n", __func__, phy->inst);
+
+ clk_put(phy->utmi_pad_clk);
+}
+
+static int utmi_phy_pad_power_on(struct tegra_usb_phy *phy)
+{
+ unsigned long val, flags;
+ void __iomem *pad_base = IO_ADDRESS(TEGRA_USB_BASE);
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ clk_enable(phy->utmi_pad_clk);
+
+ spin_lock_irqsave(&utmip_pad_lock, flags);
+
+ utmip_pad_count++;
+ val = readl(pad_base + UTMIP_BIAS_CFG0);
+ val &= ~(UTMIP_OTGPD | UTMIP_BIASPD);
+ writel(val, pad_base + UTMIP_BIAS_CFG0);
+ utmip_pad_state_on = true;
+
+ spin_unlock_irqrestore(&utmip_pad_lock, flags);
+
+ clk_disable(phy->utmi_pad_clk);
+
+ return 0;
+}
+
+static int utmi_phy_pad_power_off(struct tegra_usb_phy *phy)
+{
+ unsigned long val, flags;
+ void __iomem *pad_base = IO_ADDRESS(TEGRA_USB_BASE);
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ clk_enable(phy->utmi_pad_clk);
+ spin_lock_irqsave(&utmip_pad_lock, flags);
+
+ if (!utmip_pad_count) {
+ pr_err("%s: utmip pad already powered off\n", __func__);
+ goto out;
+ }
+ if (--utmip_pad_count == 0) {
+ val = readl(pad_base + UTMIP_BIAS_CFG0);
+ val |= UTMIP_OTGPD | UTMIP_BIASPD;
+ writel(val, pad_base + UTMIP_BIAS_CFG0);
+ utmip_pad_state_on = false;
+ }
+out:
+ spin_unlock_irqrestore(&utmip_pad_lock, flags);
+ clk_disable(phy->utmi_pad_clk);
+
+ return 0;
+}
+
+static int utmi_phy_irq(struct tegra_usb_phy *phy)
+{
+ void __iomem *base = phy->regs;
+ unsigned long val = 0;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ usb_phy_fence_read(phy);
+ if (phy->pdata->u_data.host.hot_plug) {
+ val = readl(base + USB_SUSP_CTRL);
+ if ((val & USB_PHY_CLK_VALID_INT_STS)) {
+ val &= ~USB_PHY_CLK_VALID_INT_ENB |
+ USB_PHY_CLK_VALID_INT_STS;
+ writel(val , (base + USB_SUSP_CTRL));
+ pr_info("%s: usb device plugged-in\n", __func__);
+ val = readl(base + USB_USBSTS);
+ if (!(val & USB_USBSTS_PCI))
+ return IRQ_NONE;
+ val = readl(base + USB_PORTSC);
+ val &= ~(USB_PORTSC_WKCN | USB_PORTSC_RWC_BITS);
+ writel(val , (base + USB_PORTSC));
+ }
+ } else if (!phy->phy_clk_on) {
+ return IRQ_NONE;
+ }
+
+ return IRQ_HANDLED;
+}
+
+
+static int utmi_phy_post_resume(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ val = readl(base + UTMIP_TX_CFG0);
+ val &= ~UTMIP_HS_DISCON_DISABLE;
+ writel(val, base + UTMIP_TX_CFG0);
+ return 0;
+}
+
+static int utmi_phy_pre_resume(struct tegra_usb_phy *phy, bool remote_wakeup)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ val = readl(base + UTMIP_TX_CFG0);
+ val |= UTMIP_HS_DISCON_DISABLE;
+ writel(val, base + UTMIP_TX_CFG0);
+
+ usb_phy_wait_for_sof(phy);
+
+ return 0;
+}
+
+static int utmi_phy_power_off(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (!phy->phy_clk_on) {
+ DBG("%s(%d) inst:[%d] phy clk is already off\n",
+ __func__, __LINE__, phy->inst);
+ return 0;
+ }
+
+ if (phy->pdata->op_mode == TEGRA_USB_OPMODE_DEVICE) {
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~(USB_WAKEUP_DEBOUNCE_COUNT(~0));
+ val |= USB_WAKE_ON_CNNT_EN_DEV | USB_WAKEUP_DEBOUNCE_COUNT(5);
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + UTMIP_BAT_CHRG_CFG0);
+ val |= UTMIP_PD_CHRG;
+ writel(val, base + UTMIP_BAT_CHRG_CFG0);
+ }
+
+ if (!phy->pdata->u_data.host.hot_plug) {
+ val = readl(base + UTMIP_XCVR_UHSIC_HSRX_CFG0);
+ val |= (UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN |
+ UTMIP_FORCE_PDZI_POWERDOWN);
+ writel(val, base + UTMIP_XCVR_UHSIC_HSRX_CFG0);
+ }
+
+ val = readl(base + UTMIP_XCVR_CFG1);
+ val |= UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN |
+ UTMIP_FORCE_PDDR_POWERDOWN;
+ writel(val, base + UTMIP_XCVR_CFG1);
+
+ if (phy->inst != 0) {
+ val = readl(base + UTMIP_BIAS_CFG0);
+ val |= UTMIP_OTGPD;
+ writel(val, base + UTMIP_BIAS_CFG0);
+ }
+
+ phy->port_speed = (readl(base + USB_PORTSC) >> 26) &
+ USB_PORTSC_PSPD_MASK;
+
+ if (phy->pdata->u_data.host.hot_plug) {
+ bool enable_hotplug = true;
+ /* if it is OTG port then make sure to enable hot-plug feature
+ only if host adaptor is connected, i.e id is low */
+ if (phy->pdata->port_otg) {
+ val = readl(base + USB_PHY_VBUS_WAKEUP_ID);
+ enable_hotplug = (val & USB_ID_STATUS) ? false : true;
+ }
+ if (enable_hotplug) {
+ val = readl(base + USB_PORTSC);
+ val |= USB_PORTSC_WKCN;
+ writel(val, base + USB_PORTSC);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= USB_PHY_CLK_VALID_INT_ENB;
+ writel(val, base + USB_SUSP_CTRL);
+ } else {
+ /* Disable PHY clock valid interrupts while going into suspend*/
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~USB_PHY_CLK_VALID_INT_ENB;
+ writel(val, base + USB_SUSP_CTRL);
+ }
+ }
+
+ if (phy->inst == 2) {
+ val = readl(base + USB_PORTSC);
+ val |= USB_PORTSC_PHCD;
+ writel(val, base + USB_PORTSC);
+ } else {
+ val = readl(base + USB_SUSP_CTRL);
+ val |= USB_SUSP_SET;
+ writel(val, base + USB_SUSP_CTRL);
+ udelay(10);
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~USB_SUSP_SET;
+ writel(val, base + USB_SUSP_CTRL);
+ }
+
+ if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID,
+ 0, 2500))
+ pr_warn("%s: timeout waiting for phy to stabilize\n", __func__);
+
+ utmi_phy_pad_power_off(phy);
+
+ phy->phy_clk_on = false;
+ phy->hw_accessible = false;
+
+ DBG("%s(%d) inst:[%d]END\n", __func__, __LINE__, phy->inst);
+
+ return 0;
+}
+
+static int utmi_phy_power_on(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+ struct tegra_utmi_config *config = &phy->pdata->u_cfg.utmi;
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (phy->phy_clk_on) {
+ DBG("%s(%d) inst:[%d] phy clk is already on\n",
+ __func__, __LINE__, phy->inst);
+ return 0;
+ }
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= UTMIP_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + UTMIP_TX_CFG0);
+ val |= UTMIP_FS_PREABMLE_J;
+ writel(val, base + UTMIP_TX_CFG0);
+
+ val = readl(base + UTMIP_HSRX_CFG0);
+ val &= ~(UTMIP_IDLE_WAIT(~0) | UTMIP_ELASTIC_LIMIT(~0));
+ val |= UTMIP_IDLE_WAIT(config->idle_wait_delay);
+ val |= UTMIP_ELASTIC_LIMIT(config->elastic_limit);
+ writel(val, base + UTMIP_HSRX_CFG0);
+
+ val = readl(base + UTMIP_HSRX_CFG1);
+ val &= ~(UTMIP_HS_SYNC_START_DLY(~0));
+ val |= UTMIP_HS_SYNC_START_DLY(config->hssync_start_delay);
+ writel(val, base + UTMIP_HSRX_CFG1);
+
+ val = readl(base + UTMIP_DEBOUNCE_CFG0);
+ val &= ~UTMIP_BIAS_DEBOUNCE_A(~0);
+ val |= UTMIP_BIAS_DEBOUNCE_A(phy->freq->debounce);
+ writel(val, base + UTMIP_DEBOUNCE_CFG0);
+
+ val = readl(base + UTMIP_MISC_CFG0);
+ val &= ~UTMIP_SUSPEND_EXIT_ON_EDGE;
+ writel(val, base + UTMIP_MISC_CFG0);
+
+ val = readl(base + UTMIP_MISC_CFG1);
+ val &= ~(UTMIP_PLL_ACTIVE_DLY_COUNT(~0) | UTMIP_PLLU_STABLE_COUNT(~0));
+ val |= UTMIP_PLL_ACTIVE_DLY_COUNT(phy->freq->active_delay) |
+ UTMIP_PLLU_STABLE_COUNT(phy->freq->stable_count);
+ writel(val, base + UTMIP_MISC_CFG1);
+
+ val = readl(base + UTMIP_PLL_CFG1);
+ val &= ~(UTMIP_XTAL_FREQ_COUNT(~0) | UTMIP_PLLU_ENABLE_DLY_COUNT(~0));
+ val |= UTMIP_XTAL_FREQ_COUNT(phy->freq->xtal_freq_count) |
+ UTMIP_PLLU_ENABLE_DLY_COUNT(phy->freq->enable_delay);
+ writel(val, base + UTMIP_PLL_CFG1);
+
+ if (phy->pdata->op_mode == TEGRA_USB_OPMODE_DEVICE) {
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~(USB_WAKE_ON_CNNT_EN_DEV | USB_WAKE_ON_DISCON_EN_DEV);
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + UTMIP_BAT_CHRG_CFG0);
+ val &= ~UTMIP_PD_CHRG;
+ writel(val, base + UTMIP_BAT_CHRG_CFG0);
+ } else {
+ val = readl(base + UTMIP_BAT_CHRG_CFG0);
+ val |= UTMIP_PD_CHRG;
+ writel(val, base + UTMIP_BAT_CHRG_CFG0);
+ }
+
+ utmi_phy_pad_power_on(phy);
+
+ val = readl(base + UTMIP_XCVR_UHSIC_HSRX_CFG0);
+ val &= ~(UTMIP_XCVR_LSBIAS_SEL | UTMIP_FORCE_PD_POWERDOWN |
+ UTMIP_FORCE_PD2_POWERDOWN | UTMIP_FORCE_PDZI_POWERDOWN |
+ UTMIP_XCVR_SETUP(~0) | UTMIP_XCVR_LSFSLEW(~0) |
+ UTMIP_XCVR_LSRSLEW(~0) | UTMIP_XCVR_HSSLEW_MSB(~0));
+ val |= UTMIP_XCVR_SETUP(phy->utmi_xcvr_setup);
+ val |= UTMIP_XCVR_SETUP_MSB(XCVR_SETUP_MSB_CALIB(phy->utmi_xcvr_setup));
+ val |= UTMIP_XCVR_LSFSLEW(config->xcvr_lsfslew);
+ val |= UTMIP_XCVR_LSRSLEW(config->xcvr_lsrslew);
+
+ writel(val, base + UTMIP_XCVR_UHSIC_HSRX_CFG0);
+
+ val = readl(base + UTMIP_XCVR_CFG1);
+ val &= ~(UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN |
+ UTMIP_FORCE_PDDR_POWERDOWN | UTMIP_XCVR_TERM_RANGE_ADJ(~0));
+ val |= UTMIP_XCVR_TERM_RANGE_ADJ(config->term_range_adj);
+ writel(val, base + UTMIP_XCVR_CFG1);
+
+
+ val = readl(base + UTMIP_BIAS_CFG1);
+ val &= ~(UTMIP_BIAS_PDTRK_COUNT(~0));
+ val |= UTMIP_BIAS_PDTRK_COUNT(phy->freq->pdtrk_count);
+ writel(val, base + UTMIP_BIAS_CFG1);
+
+ val = readl(base + UTMIP_SPARE_CFG0);
+ val &= ~FUSE_SETUP_SEL;
+ writel(val, base + UTMIP_SPARE_CFG0);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= UTMIP_PHY_ENABLE;
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~UTMIP_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+
+ if (phy->inst == 0) {
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~USB_SUSP_SET;
+ writel(val, base + USB_SUSP_CTRL);
+ } else {
+ val = readl(base + USB_PORTSC);
+ val &= ~USB_PORTSC_PHCD;
+ writel(val, base + USB_PORTSC);
+ }
+
+ if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL,
+ USB_PHY_CLK_VALID, USB_PHY_CLK_VALID, 2500))
+ pr_warn("%s: timeout waiting for phy to stabilize\n", __func__);
+
+ if (phy->inst == 2) {
+ val = readl(base + USB_PORTSC);
+ val &= ~(USB_PORTSC_PTS(~0));
+ writel(val, base + USB_PORTSC);
+ }
+
+ phy->phy_clk_on = true;
+ phy->hw_accessible = true;
+
+ return 0;
+}
+
+static void utmi_phy_restore_start(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ val = readl(base + UTMIP_MISC_CFG0);
+ val &= ~(UTMIP_DPDM_OBSERVE_SEL(~0));
+
+ if (phy->port_speed == USB_PHY_PORT_SPEED_LOW)
+ val |= UTMIP_DPDM_OBSERVE_SEL_FS_K;
+ else
+ val |= UTMIP_DPDM_OBSERVE_SEL_FS_J;
+ writel(val, base + UTMIP_MISC_CFG0);
+ udelay(1);
+
+ val = readl(base + UTMIP_MISC_CFG0);
+ val |= UTMIP_DPDM_OBSERVE;
+ writel(val, base + UTMIP_MISC_CFG0);
+ udelay(10);
+}
+
+static void utmi_phy_restore_end(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ val = readl(base + UTMIP_MISC_CFG0);
+ val &= ~UTMIP_DPDM_OBSERVE;
+ writel(val, base + UTMIP_MISC_CFG0);
+ udelay(10);
+}
+
+
+static int utmi_phy_resume(struct tegra_usb_phy *phy)
+{
+ int status = 0;
+ unsigned long val, flags;
+ void __iomem *base = phy->regs;
+ void __iomem *pad_base = IO_ADDRESS(TEGRA_USB_BASE);
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (phy->pdata->op_mode == TEGRA_USB_OPMODE_HOST) {
+ if (phy->port_speed < USB_PHY_PORT_SPEED_UNKNOWN) {
+ utmi_phy_restore_start(phy);
+ usb_phy_bringup_host_controller(phy);
+ utmi_phy_restore_end(phy);
+ } else {
+ /* device is plugged in when system is in LP0 */
+ /* bring up the controller from LP0*/
+ val = readl(base + USB_USBCMD);
+ val |= USB_USBCMD_RESET;
+ writel(val, base + USB_USBCMD);
+
+ if (usb_phy_reg_status_wait(base + USB_USBCMD,
+ USB_USBCMD_RESET, 0, 2500) < 0) {
+ pr_err("%s: timeout waiting for reset\n", __func__);
+ }
+
+ val = readl(base + USB_USBMODE_REG_OFFSET);
+ val &= ~USB_USBMODE_MASK;
+ val |= USB_USBMODE_HOST;
+ writel(val, base + USB_USBMODE_REG_OFFSET);
+
+ if (phy->inst == 2) {
+ val = readl(base + USB_PORTSC);
+ val &= ~USB_PORTSC_PTS(~0);
+ writel(val, base + USB_PORTSC);
+ }
+ writel(USB_USBCMD_RS, base + USB_USBCMD);
+
+ if (usb_phy_reg_status_wait(base + USB_USBCMD,
+ USB_USBCMD_RS, USB_USBCMD_RS, 2500) < 0) {
+ pr_err("%s: timeout waiting for run bit\n", __func__);
+ }
+
+ /* Enable Port Power */
+ val = readl(base + USB_PORTSC);
+ val |= USB_PORTSC_PP;
+ writel(val, base + USB_PORTSC);
+ udelay(10);
+
+ DBG("USB_USBSTS[0x%x] USB_PORTSC[0x%x]\n",
+ readl(base + USB_USBSTS), readl(base + USB_PORTSC));
+ }
+ } else {
+ /* Restoring the pad powers */
+ clk_enable(phy->utmi_pad_clk);
+
+ spin_lock_irqsave(&utmip_pad_lock, flags);
+
+ val = readl(pad_base + UTMIP_BIAS_CFG0);
+ if (utmip_pad_state_on)
+ val &= ~(UTMIP_OTGPD | UTMIP_BIASPD);
+ else
+ val |= (UTMIP_OTGPD | UTMIP_BIASPD);
+ writel(val, pad_base + UTMIP_BIAS_CFG0);
+
+ spin_unlock_irqrestore(&utmip_pad_lock, flags);
+ clk_disable(phy->utmi_pad_clk);
+ }
+
+ return status;
+}
+
+static bool utmi_phy_charger_detect(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+ bool status;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ /* Enable charger detection logic */
+ val = readl(base + UTMIP_BAT_CHRG_CFG0);
+ val |= UTMIP_OP_SRC_EN | UTMIP_ON_SINK_EN;
+ writel(val, base + UTMIP_BAT_CHRG_CFG0);
+
+ /* Source should be on for 100 ms as per USB charging spec */
+ msleep(TDP_SRC_ON_MS);
+
+ val = readl(base + USB_PHY_VBUS_WAKEUP_ID);
+ /* If charger is not connected disable the interrupt */
+ val &= ~VDAT_DET_INT_EN;
+ val |= VDAT_DET_CHG_DET;
+ writel(val, base + USB_PHY_VBUS_WAKEUP_ID);
+
+ val = readl(base + USB_PHY_VBUS_WAKEUP_ID);
+ if (val & VDAT_DET_STS)
+ status = true;
+ else
+ status = false;
+
+ /* Disable charger detection logic */
+ val = readl(base + UTMIP_BAT_CHRG_CFG0);
+ val &= ~(UTMIP_OP_SRC_EN | UTMIP_ON_SINK_EN);
+ writel(val, base + UTMIP_BAT_CHRG_CFG0);
+
+ /* Delay of 40 ms before we pull the D+ as per battery charger spec */
+ msleep(TDPSRC_CON_MS);
+
+ return status;
+}
+
+
+static int uhsic_phy_open(struct tegra_usb_phy *phy)
+{
+ unsigned long parent_rate;
+ int i;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ parent_rate = clk_get_rate(clk_get_parent(phy->pllu_clk));
+ for (i = 0; i < ARRAY_SIZE(uhsic_freq_table); i++) {
+ if (uhsic_freq_table[i].freq == parent_rate) {
+ phy->freq = &uhsic_freq_table[i];
+ break;
+ }
+ }
+ if (!phy->freq) {
+ pr_err("invalid pll_u parent rate %ld\n", parent_rate);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int uhsic_phy_irq(struct tegra_usb_phy *phy)
+{
+ usb_phy_fence_read(phy);
+ return IRQ_HANDLED;
+}
+
+static int uhsic_phy_power_on(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+ struct tegra_hsic_config *config = &phy->pdata->u_cfg.hsic;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (phy->phy_clk_on) {
+ DBG("%s(%d) inst:[%d] phy clk is already On\n", __func__,
+ __LINE__, phy->inst);
+ return 0;
+ }
+
+ val = readl(base + UHSIC_PADS_CFG1);
+ val &= ~(UHSIC_PD_BG | UHSIC_PD_TX | UHSIC_PD_TRK | UHSIC_PD_RX |
+ UHSIC_PD_ZI | UHSIC_RPD_DATA | UHSIC_RPD_STROBE);
+ val |= UHSIC_RX_SEL;
+ writel(val, base + UHSIC_PADS_CFG1);
+ udelay(2);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= UHSIC_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+ udelay(30);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= UHSIC_PHY_ENABLE;
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + UTMIP_XCVR_UHSIC_HSRX_CFG0);
+ val |= UHSIC_IDLE_WAIT(config->idle_wait_delay);
+ val |= UHSIC_ELASTIC_UNDERRUN_LIMIT(config->elastic_underrun_limit);
+ val |= UHSIC_ELASTIC_OVERRUN_LIMIT(config->elastic_overrun_limit);
+ writel(val, base + UTMIP_XCVR_UHSIC_HSRX_CFG0);
+
+ val = readl(base + UHSIC_HSRX_CFG1);
+ val |= UHSIC_HS_SYNC_START_DLY(config->sync_start_delay);
+ writel(val, base + UHSIC_HSRX_CFG1);
+
+ val = readl(base + UHSIC_MISC_CFG0);
+ val |= UHSIC_SUSPEND_EXIT_ON_EDGE;
+ writel(val, base + UHSIC_MISC_CFG0);
+
+ val = readl(base + UHSIC_MISC_CFG1);
+ val |= UHSIC_PLLU_STABLE_COUNT(phy->freq->stable_count);
+ writel(val, base + UHSIC_MISC_CFG1);
+
+ val = readl(base + UHSIC_PLL_CFG1);
+ val |= UHSIC_PLLU_ENABLE_DLY_COUNT(phy->freq->enable_delay);
+ val |= UHSIC_XTAL_FREQ_COUNT(phy->freq->xtal_freq_count);
+ writel(val, base + UHSIC_PLL_CFG1);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~(UHSIC_RESET);
+ writel(val, base + USB_SUSP_CTRL);
+ udelay(2);
+
+ val = readl(base + USB_PORTSC);
+ val &= ~(USB_PORTSC_PTS(~0));
+ writel(val, base + USB_PORTSC);
+
+ val = readl(base + USB_TXFILLTUNING);
+ if ((val & USB_FIFO_TXFILL_MASK) != USB_FIFO_TXFILL_THRES(0x10)) {
+ val = USB_FIFO_TXFILL_THRES(0x10);
+ writel(val, base + USB_TXFILLTUNING);
+ }
+
+ val = readl(base + USB_PORTSC);
+ val &= ~(USB_PORTSC_WKOC | USB_PORTSC_WKDS | USB_PORTSC_WKCN);
+ writel(val, base + USB_PORTSC);
+
+ val = readl(base + UHSIC_PADS_CFG0);
+ val &= ~(UHSIC_TX_RTUNEN);
+ /* set Rtune impedance to 40 ohm */
+ val |= UHSIC_TX_RTUNE(0);
+ writel(val, base + UHSIC_PADS_CFG0);
+
+ if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID,
+ USB_PHY_CLK_VALID, 2500)) {
+ pr_err("%s: timeout waiting for phy to stabilize\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ phy->phy_clk_on = true;
+ phy->hw_accessible = true;
+
+ return 0;
+}
+
+static int uhsic_phy_power_off(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (!phy->phy_clk_on) {
+ DBG("%s(%d) inst:[%d] phy clk is already off\n", __func__,
+ __LINE__, phy->inst);
+ return 0;
+ }
+
+ val = readl(base + UHSIC_PADS_CFG1);
+ val &= ~UHSIC_RPU_STROBE;
+ val |= UHSIC_RPD_STROBE;
+ writel(val, base + UHSIC_PADS_CFG1);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= UHSIC_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+ udelay(30);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~UHSIC_PHY_ENABLE;
+ writel(val, base + USB_SUSP_CTRL);
+
+ phy->phy_clk_on = false;
+ phy->hw_accessible = false;
+
+ return 0;
+}
+
+static int uhsic_phy_bus_port_power(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ val = readl(base + UHSIC_MISC_CFG0);
+ val |= UHSIC_DETECT_SHORT_CONNECT;
+ writel(val, base + UHSIC_MISC_CFG0);
+ udelay(1);
+
+ val = readl(base + UHSIC_MISC_CFG0);
+ val |= UHSIC_FORCE_XCVR_MODE;
+ writel(val, base + UHSIC_MISC_CFG0);
+
+ val = readl(base + UHSIC_PADS_CFG1);
+ val &= ~UHSIC_RPD_STROBE;
+ val |= UHSIC_RPU_STROBE;
+ writel(val, base + UHSIC_PADS_CFG1);
+
+ val = readl(base + USB_USBCMD);
+ val &= ~USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+
+ if (phy->pdata->ops && phy->pdata->ops->port_power)
+ phy->pdata->ops->port_power();
+
+ if (usb_phy_reg_status_wait(base + UHSIC_STAT_CFG0,
+ UHSIC_CONNECT_DETECT, UHSIC_CONNECT_DETECT, 2000)) {
+ pr_err("%s: timeout waiting for UHSIC_CONNECT_DETECT\n",
+ __func__);
+ return -ETIMEDOUT;
+ }
+
+/* FIXME : need to check whether this piece is required or not
+ if (usb_phy_reg_status_wait(base + USB_PORTSC, USB_PORTSC_LS(2),
+ USB_PORTSC_LS(2), 2000)) {
+ pr_err("%s: timeout waiting for dplus state\n", __func__);
+ return -ETIMEDOUT;
+ }
+*/
+ return 0;
+}
+
+
+static int uhsic_phy_bus_reset(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ val = readl(base + USB_PORTSC);
+ val |= USB_PORTSC_PTC(5);
+ writel(val, base + USB_PORTSC);
+ udelay(2);
+
+ val = readl(base + USB_PORTSC);
+ val &= ~(USB_PORTSC_PTC(~0));
+ writel(val, base + USB_PORTSC);
+ udelay(2);
+
+ if (usb_phy_reg_status_wait(base + USB_PORTSC, USB_PORTSC_LS(0),
+ 0, 2000)) {
+ pr_err("%s: timeout waiting for USB_PORTSC_LS\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ /* Poll until CCS is enabled */
+ if (usb_phy_reg_status_wait(base + USB_PORTSC, USB_PORTSC_CCS,
+ USB_PORTSC_CCS, 2000)) {
+ pr_err("%s: timeout waiting for USB_PORTSC_CCS\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ if (usb_phy_reg_status_wait(base + USB_PORTSC, USB_PORTSC_PSPD(2),
+ USB_PORTSC_PSPD(2), 2000)) {
+ pr_err("%s: timeout waiting for USB_PORTSC_PSPD\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ val = readl(base + USB_USBCMD);
+ val &= ~USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+
+ if (usb_phy_reg_status_wait(base + USB_USBSTS, USB_USBSTS_HCH,
+ USB_USBSTS_HCH, 2000)) {
+ pr_err("%s: timeout waiting for USB_USBSTS_HCH\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ val = readl(base + UHSIC_PADS_CFG1);
+ val &= ~UHSIC_RPU_STROBE;
+ val |= UHSIC_RPD_STROBE;
+ writel(val, base + UHSIC_PADS_CFG1);
+
+ mdelay(50);
+
+ val = readl(base + UHSIC_PADS_CFG1);
+ val &= ~UHSIC_RPD_STROBE;
+ val |= UHSIC_RPU_STROBE;
+ writel(val, base + UHSIC_PADS_CFG1);
+
+ val = readl(base + USB_USBCMD);
+ val |= USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+
+ val = readl(base + UHSIC_PADS_CFG1);
+ val &= ~UHSIC_RPU_STROBE;
+ writel(val, base + UHSIC_PADS_CFG1);
+
+ if (usb_phy_reg_status_wait(base + USB_USBCMD, USB_USBCMD_RS,
+ USB_USBCMD_RS, 2000)) {
+ pr_err("%s: timeout waiting for USB_USBCMD_RS\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+
+static int uhsic_phy_pre_resume(struct tegra_usb_phy *phy, bool remote_wakeup)
+{
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ usb_phy_wait_for_sof(phy);
+
+ return 0;
+}
+
+static int uhsic_phy_resume(struct tegra_usb_phy *phy)
+{
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ uhsic_phy_bus_port_power(phy);
+
+ return 0;
+}
+
+
+static int uhsic_phy_post_resume(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ val = readl(base + USB_TXFILLTUNING);
+ if ((val & USB_FIFO_TXFILL_MASK) != USB_FIFO_TXFILL_THRES(0x10)) {
+ val = USB_FIFO_TXFILL_THRES(0x10);
+ writel(val, base + USB_TXFILLTUNING);
+ }
+
+ return 0;
+}
+
+static void ulpi_set_trimmer(struct tegra_usb_phy *phy)
+{
+ struct tegra_ulpi_config *config = &phy->pdata->u_cfg.ulpi;
+ void __iomem *base = phy->regs;
+ unsigned long val;
+
+ val = ULPI_DATA_TRIMMER_SEL(config->data_trimmer);
+ val |= ULPI_STPDIRNXT_TRIMMER_SEL(config->stpdirnxt_trimmer);
+ val |= ULPI_DIR_TRIMMER_SEL(config->dir_trimmer);
+ writel(val, base + ULPI_TIMING_CTRL_1);
+ udelay(10);
+
+ val |= ULPI_DATA_TRIMMER_LOAD;
+ val |= ULPI_STPDIRNXT_TRIMMER_LOAD;
+ val |= ULPI_DIR_TRIMMER_LOAD;
+ writel(val, base + ULPI_TIMING_CTRL_1);
+}
+
+
+static int ulpi_link_phy_open(struct tegra_usb_phy *phy)
+{
+ struct tegra_ulpi_config *config = &phy->pdata->u_cfg.ulpi;
+ int err = 0;
+
+ phy->ulpi_clk = NULL;
+
+ if (config->clk) {
+ phy->ulpi_clk = clk_get_sys(NULL, config->clk);
+ if (IS_ERR(phy->ulpi_clk)) {
+ pr_err("%s: can't get ulpi clock\n", __func__);
+ err = -ENXIO;
+ }
+ }
+
+ phy->ulpi_vp = otg_ulpi_create(&ulpi_viewport_access_ops, 0);
+ phy->ulpi_vp->io_priv = phy->regs + ULPI_VIEWPORT;
+
+ return err;
+}
+
+static void ulpi_link_phy_close(struct tegra_usb_phy *phy)
+{
+ DBG("%s inst:[%d]\n", __func__, phy->inst);
+ if (phy->ulpi_clk)
+ clk_put(phy->ulpi_clk);
+}
+
+static int ulpi_link_phy_irq(struct tegra_usb_phy *phy)
+{
+ usb_phy_fence_read(phy);
+ return IRQ_HANDLED;
+}
+
+static int ulpi_link_phy_power_off(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+ int ret;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (!phy->phy_clk_on) {
+ DBG("%s(%d) inst:[%d] phy clk is already off\n", __func__,
+ __LINE__, phy->inst);
+ return 0;
+ }
+
+ /* Disable VbusValid, SessEnd comparators */
+ ret = otg_io_write(phy->ulpi_vp, 0x00, 0x0D);
+ if (ret)
+ pr_err("%s: ulpi write 0x0D failed\n", __func__);
+
+ ret = otg_io_write(phy->ulpi_vp, 0x00, 0x10);
+ if (ret)
+ pr_err("%s: ulpi write 0x10 failed\n", __func__);
+
+ /* Disable IdFloat comparator */
+ ret = otg_io_write(phy->ulpi_vp, 0x00, 0x19);
+ if (ret)
+ pr_err("%s: ulpi write 0x19 failed\n", __func__);
+
+ ret = otg_io_write(phy->ulpi_vp, 0x00, 0x1D);
+ if (ret)
+ pr_err("%s: ulpi write 0x1D failed\n", __func__);
+
+ phy->port_speed = (readl(base + USB_PORTSC) >> 26) &
+ USB_PORTSC_PSPD_MASK;
+
+ /* Clear WKCN/WKDS/WKOC wake-on events that can cause the USB
+ * Controller to immediately bring the ULPI PHY out of low power
+ */
+ val = readl(base + USB_PORTSC);
+ val &= ~(USB_PORTSC_WKOC | USB_PORTSC_WKDS | USB_PORTSC_WKCN);
+ writel(val, base + USB_PORTSC);
+
+ /* Put the PHY in the low power mode */
+ val = readl(base + USB_PORTSC);
+ val |= USB_PORTSC_PHCD;
+ writel(val, base + USB_PORTSC);
+
+ if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID,
+ 0, 2500)) {
+ pr_err("%s: timeout waiting for phy to stop\n", __func__);
+ }
+
+ if (phy->ulpi_clk)
+ clk_disable(phy->ulpi_clk);
+
+ phy->phy_clk_on = false;
+ phy->hw_accessible = false;
+
+ return 0;
+}
+
+static int ulpi_link_phy_power_on(struct tegra_usb_phy *phy)
+{
+ int ret;
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (phy->phy_clk_on) {
+ DBG("%s(%d) inst:[%d] phy clk is already On\n", __func__,
+ __LINE__, phy->inst);
+ return 0;
+ }
+
+ if (phy->ulpi_clk) {
+ clk_enable(phy->ulpi_clk);
+ mdelay(1);
+ }
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= UHSIC_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_OUTPUT_PINMUX_BYP | ULPI_CLKOUT_PINMUX_BYP;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= ULPI_PHY_ENABLE;
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= USB_SUSP_CLR;
+ writel(val, base + USB_SUSP_CTRL);
+
+ if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID,
+ USB_PHY_CLK_VALID, 2500))
+ pr_err("%s: timeout waiting for phy to stabilize\n", __func__);
+
+ if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL, USB_CLKEN,
+ USB_CLKEN, 2500))
+ pr_err("%s: timeout waiting for AHB clock\n", __func__);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~USB_SUSP_CLR;
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = 0;
+ writel(val, base + ULPI_TIMING_CTRL_1);
+
+ ulpi_set_trimmer(phy);
+
+ /* Fix VbusInvalid due to floating VBUS */
+ ret = otg_io_write(phy->ulpi_vp, 0x40, 0x08);
+ if (ret) {
+ pr_err("%s: ulpi write failed\n", __func__);
+ return ret;
+ }
+
+ ret = otg_io_write(phy->ulpi_vp, 0x80, 0x0B);
+ if (ret) {
+ pr_err("%s: ulpi write failed\n", __func__);
+ return ret;
+ }
+
+ val = readl(base + USB_PORTSC);
+ val |= USB_PORTSC_WKOC | USB_PORTSC_WKDS | USB_PORTSC_WKCN;
+ writel(val, base + USB_PORTSC);
+
+ phy->phy_clk_on = true;
+ phy->hw_accessible = true;
+
+ return 0;
+}
+
+static inline void ulpi_link_phy_set_tristate(bool enable)
+{
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ int tristate = (enable) ? TEGRA_TRI_TRISTATE : TEGRA_TRI_NORMAL;
+
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAA, tristate);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAB, tristate);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_UDA, tristate);
+#endif
+}
+
+static void ulpi_link_phy_restore_start(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ /*Tristate ulpi interface before USB controller resume*/
+ ulpi_link_phy_set_tristate(true);
+
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val &= ~ULPI_OUTPUT_PINMUX_BYP;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+}
+
+static void ulpi_link_phy_restore_end(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_OUTPUT_PINMUX_BYP;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+
+ ulpi_link_phy_set_tristate(false);
+}
+
+static int ulpi_link_phy_resume(struct tegra_usb_phy *phy)
+{
+ int status = 0;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (phy->pdata->u_data.host.power_off_on_suspend) {
+ status = ulpi_link_phy_power_on(phy);
+ if (phy->port_speed < USB_PHY_PORT_SPEED_UNKNOWN) {
+ ulpi_link_phy_restore_start(phy);
+ usb_phy_bringup_host_controller(phy);
+ ulpi_link_phy_restore_end(phy);
+ }
+ }
+
+ return status;
+}
+
+static inline void ulpi_pinmux_bypass(struct tegra_usb_phy *phy, bool enable)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ val = readl(base + ULPI_TIMING_CTRL_0);
+
+ if (enable)
+ val |= ULPI_OUTPUT_PINMUX_BYP;
+ else
+ val &= ~ULPI_OUTPUT_PINMUX_BYP;
+
+ writel(val, base + ULPI_TIMING_CTRL_0);
+}
+
+static inline void ulpi_null_phy_set_tristate(bool enable)
+{
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ int tristate = (enable) ? TEGRA_TRI_TRISTATE : TEGRA_TRI_NORMAL;
+
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_UDA, tristate);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAA, tristate);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAB, tristate);
+#endif
+}
+
+static void ulpi_null_phy_obs_read(void)
+{
+ static void __iomem *apb_misc;
+ unsigned slv0_obs, s2s_obs;
+
+ if (!apb_misc)
+ apb_misc = ioremap(TEGRA_APB_MISC_BASE, TEGRA_APB_MISC_SIZE);
+
+ writel(0x80b10034, apb_misc + APB_MISC_GP_OBSCTRL_0);
+ slv0_obs = readl(apb_misc + APB_MISC_GP_OBSDATA_0);
+
+ writel(0x80b10038, apb_misc + APB_MISC_GP_OBSCTRL_0);
+ s2s_obs = readl(apb_misc + APB_MISC_GP_OBSDATA_0);
+
+ pr_debug("slv0 obs: %08x\ns2s obs: %08x\n", slv0_obs, s2s_obs);
+}
+
+static const struct gpio ulpi_gpios[] = {
+ {ULPI_STP, GPIOF_IN, "ULPI_STP"},
+ {ULPI_DIR, GPIOF_OUT_INIT_LOW, "ULPI_DIR"},
+ {ULPI_D0, GPIOF_OUT_INIT_LOW, "ULPI_D0"},
+ {ULPI_D1, GPIOF_OUT_INIT_LOW, "ULPI_D1"},
+};
+
+static int ulpi_null_phy_open(struct tegra_usb_phy *phy)
+{
+ struct tegra_ulpi_config *config = &phy->pdata->u_cfg.ulpi;
+ int ret;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ ret = gpio_request_array(ulpi_gpios, ARRAY_SIZE(ulpi_gpios));
+ if (ret)
+ return ret;
+
+ if (gpio_is_valid(config->phy_restore_gpio)) {
+ ret = gpio_request(config->phy_restore_gpio, "phy_restore");
+ if (ret)
+ goto err_gpio_free;
+
+ gpio_direction_input(config->phy_restore_gpio);
+ }
+
+ tegra_periph_reset_assert(phy->ctrlr_clk);
+ udelay(10);
+ tegra_periph_reset_deassert(phy->ctrlr_clk);
+
+ return 0;
+
+err_gpio_free:
+ gpio_free_array(ulpi_gpios, ARRAY_SIZE(ulpi_gpios));
+ return ret;
+}
+
+static void ulpi_null_phy_close(struct tegra_usb_phy *phy)
+{
+ struct tegra_ulpi_config *config = &phy->pdata->u_cfg.ulpi;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ if (gpio_is_valid(config->phy_restore_gpio))
+ gpio_free(config->phy_restore_gpio);
+
+ gpio_free_array(ulpi_gpios, ARRAY_SIZE(ulpi_gpios));
+}
+
+static int ulpi_null_phy_power_off(struct tegra_usb_phy *phy)
+{
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ if (!phy->phy_clk_on) {
+ DBG("%s(%d) inst:[%d] phy clk is already off\n", __func__,
+ __LINE__, phy->inst);
+ return 0;
+ }
+
+ phy->phy_clk_on = false;
+ phy->hw_accessible = false;
+ ulpi_null_phy_set_tristate(true);
+ return 0;
+}
+
+static int ulpi_null_phy_irq(struct tegra_usb_phy *phy)
+{
+ usb_phy_fence_read(phy);
+ return IRQ_HANDLED;
+}
+
+static int ulpi_null_phy_restore(struct tegra_usb_phy *phy)
+{
+ struct tegra_ulpi_config *config = &phy->pdata->u_cfg.ulpi;
+ unsigned long timeout;
+ int ulpi_stp = ULPI_STP;
+
+ if (gpio_is_valid(config->phy_restore_gpio))
+ ulpi_stp = config->phy_restore_gpio;
+
+ /* disable ULPI pinmux bypass */
+ ulpi_pinmux_bypass(phy, false);
+
+ /* driving linstate by GPIO */
+ gpio_set_value(ULPI_D0, 0);
+ gpio_set_value(ULPI_D1, 0);
+
+ /* driving DIR high */
+ gpio_set_value(ULPI_DIR, 1);
+
+ /* remove ULPI tristate */
+ ulpi_null_phy_set_tristate(false);
+
+ /* wait for STP high */
+ timeout = jiffies + msecs_to_jiffies(25);
+
+ while (!gpio_get_value(ulpi_stp)) {
+ if (time_after(jiffies, timeout)) {
+ pr_warn("phy restore timeout\n");
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int ulpi_null_phy_lp0_resume(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ val = readl(base + USB_USBCMD);
+ val |= USB_USBCMD_RESET;
+ writel(val, base + USB_USBCMD);
+
+ if (usb_phy_reg_status_wait(base + USB_USBCMD,
+ USB_USBCMD_RESET, 0, 2500) < 0) {
+ pr_err("%s: timeout waiting for reset\n", __func__);
+ }
+
+ val = readl(base + USB_USBMODE_REG_OFFSET);
+ val &= ~USB_USBMODE_MASK;
+ val |= USB_USBMODE_HOST;
+ writel(val, base + USB_USBMODE_REG_OFFSET);
+
+ val = readl(base + USB_USBCMD);
+ val |= USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+ if (usb_phy_reg_status_wait(base + USB_USBCMD, USB_USBCMD_RS,
+ USB_USBCMD_RS, 2000)) {
+ pr_err("%s: timeout waiting for USB_USBCMD_RS\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ /* Enable Port Power */
+ val = readl(base + USB_PORTSC);
+ val |= USB_PORTSC_PP;
+ writel(val, base + USB_PORTSC);
+ udelay(10);
+
+ ulpi_null_phy_restore(phy);
+
+ return 0;
+}
+
+static int ulpi_null_phy_power_on(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+ struct tegra_ulpi_config *config = &phy->pdata->u_cfg.ulpi;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (phy->phy_clk_on) {
+ DBG("%s(%d) inst:[%d] phy clk is already On\n", __func__,
+ __LINE__, phy->inst);
+ return 0;
+ }
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= UHSIC_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_OUTPUT_PINMUX_BYP | ULPI_CLKOUT_PINMUX_BYP;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= ULPI_PHY_ENABLE;
+ writel(val, base + USB_SUSP_CTRL);
+ udelay(10);
+
+ /* set timming parameters */
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_SHADOW_CLK_LOOPBACK_EN;
+ val |= ULPI_SHADOW_CLK_SEL;
+ val |= ULPI_LBK_PAD_EN;
+ val |= ULPI_SHADOW_CLK_DELAY(config->shadow_clk_delay);
+ val |= ULPI_CLOCK_OUT_DELAY(config->clock_out_delay);
+ val |= ULPI_LBK_PAD_E_INPUT_OR;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+
+ writel(0, base + ULPI_TIMING_CTRL_1);
+ udelay(10);
+
+ /* start internal 60MHz clock */
+ val = readl(base + ULPIS2S_CTRL);
+ val |= ULPIS2S_ENA;
+ val |= ULPIS2S_SUPPORT_DISCONNECT;
+ val |= ULPIS2S_SPARE((phy->pdata->op_mode == TEGRA_USB_OPMODE_HOST) ? 3 : 1);
+ val |= ULPIS2S_PLLU_MASTER_BLASTER60;
+ writel(val, base + ULPIS2S_CTRL);
+
+ /* select ULPI_CORE_CLK_SEL to SHADOW_CLK */
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_CORE_CLK_SEL;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+ udelay(10);
+
+ /* enable ULPI null phy clock - can't set the trimmers before this */
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_CLK_OUT_ENA;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+ udelay(10);
+
+ if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID,
+ USB_PHY_CLK_VALID, 2500)) {
+ pr_err("%s: timeout waiting for phy to stabilize\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ /* set ULPI trimmers */
+ ulpi_set_trimmer(phy);
+
+ if (!phy->ulpi_clk_padout_ena) {
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_CLK_PADOUT_ENA;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+ phy->ulpi_clk_padout_ena = true;
+ } else {
+ if (!readl(base + USB_ASYNCLISTADDR))
+ ulpi_null_phy_lp0_resume(phy);
+ }
+ udelay(10);
+
+ phy->phy_clk_on = true;
+ phy->hw_accessible = true;
+
+ return 0;
+}
+
+static int ulpi_null_phy_pre_resume(struct tegra_usb_phy *phy,
+ bool remote_wakeup)
+{
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ ulpi_null_phy_obs_read();
+ usb_phy_wait_for_sof(phy);
+ ulpi_null_phy_obs_read();
+ return 0;
+}
+
+static int ulpi_null_phy_post_resume(struct tegra_usb_phy *phy)
+{
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ ulpi_null_phy_obs_read();
+ return 0;
+}
+
+static int ulpi_null_phy_resume(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ if (!readl(base + USB_ASYNCLISTADDR)) {
+ /* enable ULPI CLK output pad */
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_CLK_PADOUT_ENA;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+
+ /* enable ULPI pinmux bypass */
+ ulpi_pinmux_bypass(phy, true);
+ udelay(5);
+ }
+
+ return 0;
+}
+
+
+
+static struct tegra_usb_phy_ops utmi_phy_ops = {
+ .open = utmi_phy_open,
+ .close = utmi_phy_close,
+ .irq = utmi_phy_irq,
+ .power_on = utmi_phy_power_on,
+ .power_off = utmi_phy_power_off,
+ .pre_resume = utmi_phy_pre_resume,
+ .resume = utmi_phy_resume,
+ .post_resume = utmi_phy_post_resume,
+ .charger_detect = utmi_phy_charger_detect,
+};
+
+static struct tegra_usb_phy_ops uhsic_phy_ops = {
+ .open = uhsic_phy_open,
+ .irq = uhsic_phy_irq,
+ .power_on = uhsic_phy_power_on,
+ .power_off = uhsic_phy_power_off,
+ .pre_resume = uhsic_phy_pre_resume,
+ .resume = uhsic_phy_resume,
+ .post_resume = uhsic_phy_post_resume,
+ .port_power = uhsic_phy_bus_port_power,
+ .bus_reset = uhsic_phy_bus_reset,
+};
+
+static struct tegra_usb_phy_ops ulpi_link_phy_ops = {
+ .open = ulpi_link_phy_open,
+ .close = ulpi_link_phy_close,
+ .irq = ulpi_link_phy_irq,
+ .power_on = ulpi_link_phy_power_on,
+ .power_off = ulpi_link_phy_power_off,
+ .resume = ulpi_link_phy_resume,
+};
+
+static struct tegra_usb_phy_ops ulpi_null_phy_ops = {
+ .open = ulpi_null_phy_open,
+ .close = ulpi_null_phy_close,
+ .irq = ulpi_null_phy_irq,
+ .power_on = ulpi_null_phy_power_on,
+ .power_off = ulpi_null_phy_power_off,
+ .pre_resume = ulpi_null_phy_pre_resume,
+ .resume = ulpi_null_phy_resume,
+ .post_resume = ulpi_null_phy_post_resume,
+};
+
+static struct tegra_usb_phy_ops icusb_phy_ops;
+
+
+static struct tegra_usb_phy_ops *phy_ops[] = {
+ [TEGRA_USB_PHY_INTF_UTMI] = &utmi_phy_ops,
+ [TEGRA_USB_PHY_INTF_ULPI_LINK] = &ulpi_link_phy_ops,
+ [TEGRA_USB_PHY_INTF_ULPI_NULL] = &ulpi_null_phy_ops,
+ [TEGRA_USB_PHY_INTF_HSIC] = &uhsic_phy_ops,
+ [TEGRA_USB_PHY_INTF_ICUSB] = &icusb_phy_ops,
+};
+
+int tegra2_usb_phy_init_ops(struct tegra_usb_phy *phy)
+{
+ phy->ops = phy_ops[phy->pdata->phy_intf];
+
+ return 0;
+}
diff --git a/arch/arm/mach-tegra/tegra3_actmon.c b/arch/arm/mach-tegra/tegra3_actmon.c
index 5df6ed1fc471..a76d0a963d90 100644
--- a/arch/arm/mach-tegra/tegra3_actmon.c
+++ b/arch/arm/mach-tegra/tegra3_actmon.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 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
@@ -532,7 +532,7 @@ static struct actmon_dev actmon_dev_avp = {
.boost_freq_step = 8000,
.boost_up_coef = 200,
.boost_down_coef = 50,
- .boost_up_threshold = 75,
+ .boost_up_threshold = 85,
.boost_down_threshold = 50,
.up_wmark_window = 1,
diff --git a/arch/arm/mach-tegra/tegra3_clocks.c b/arch/arm/mach-tegra/tegra3_clocks.c
index 262b7a5cedad..110c8d4e601c 100644
--- a/arch/arm/mach-tegra/tegra3_clocks.c
+++ b/arch/arm/mach-tegra/tegra3_clocks.c
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/tegra3_clocks.c
*
- * 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 of the GNU General Public License as published by
@@ -228,6 +228,14 @@
#define PMC_PLLP_WB0_OVERRIDE 0xf8
#define PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE (1 << 12)
+#define PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE (1 << 11)
+#define PMC_PLLM_WB0_OVERRIDE 0x1dc
+#define PMC_PLLM_WB0_OVERRIDE_DIVP_MASK (0x7<<15)
+#define PMC_PLLM_WB0_OVERRIDE_DIVP_SHIFT 15
+#define PMC_PLLM_WB0_OVERRIDE_DIVN_MASK (0x3FF<<5)
+#define PMC_PLLM_WB0_OVERRIDE_DIVN_SHIFT 5
+#define PMC_PLLM_WB0_OVERRIDE_DIVM_MASK (0x1F)
+#define PMC_PLLM_WB0_OVERRIDE_DIVM_SHIFT 0
#define UTMIP_PLL_CFG2 0x488
#define UTMIP_PLL_CFG2_STABLE_COUNT(x) (((x) & 0xfff) << 6)
@@ -284,7 +292,7 @@
#define PLLE_SS_COEFFICIENTS_12MHZ \
((0x18<<PLLE_SS_INCINTRV_SHIFT) | (0x1<<PLLE_SS_INC_SHIFT) | \
(0x24<<PLLE_SS_MAX_SHIFT))
-#define PLLE_SS_DISABLE ((1<<12) | (1<<11) | (1<<10))
+#define PLLE_SS_DISABLE ((1<<14) | (1<<12) | (1<<11) | (1<<10))
#define PLLE_AUX 0x48c
#define PLLE_AUX_PLLP_SEL (1<<2)
@@ -306,6 +314,8 @@
static void tegra3_pllp_init_dependencies(unsigned long pllp_rate);
static int tegra3_clk_shared_bus_update(struct clk *bus);
+static int tegra3_emc_relock_set_rate(struct clk *emc, unsigned long old_rate,
+ unsigned long new_rate, unsigned long new_pll_rate);
static unsigned long cpu_stay_on_backup_max;
static struct clk *emc_bridge;
@@ -1457,6 +1467,30 @@ static void tegra3_utmi_param_configure(struct clk *c)
clk_writel(reg, UTMIP_PLL_CFG1);
}
+static void tegra3_pll_m_override_update(struct clk *c, bool init)
+{
+ u32 val = pmc_readl(PMC_PLLP_WB0_OVERRIDE);
+
+ if (!(val & PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE))
+ return;
+
+ /* override PLLM state with PMC settings */
+ c->state = (val & PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE) ? ON : OFF;
+
+ val = pmc_readl(PMC_PLLM_WB0_OVERRIDE);
+ c->mul = (val & PMC_PLLM_WB0_OVERRIDE_DIVN_MASK) >>
+ PMC_PLLM_WB0_OVERRIDE_DIVN_SHIFT;
+ c->div = (val & PMC_PLLM_WB0_OVERRIDE_DIVM_MASK) >>
+ PMC_PLLM_WB0_OVERRIDE_DIVM_SHIFT;
+ c->div *= (0x1 << ((val & PMC_PLLM_WB0_OVERRIDE_DIVP_MASK) >>
+ PMC_PLLM_WB0_OVERRIDE_DIVP_SHIFT));
+
+ /* Save initial override settings in Scratch2 register; will be used by
+ LP0 entry code to restore PLLM boot configuration */
+ if (init)
+ pmc_writel(val, PMC_SCRATCH2);
+}
+
static void tegra3_pll_clk_init(struct clk *c)
{
u32 val = clk_readl(c->reg + PLL_BASE);
@@ -1498,6 +1532,9 @@ static void tegra3_pll_clk_init(struct clk *c)
if (c->flags & PLLU) {
tegra3_utmi_param_configure(c);
}
+
+ if (c->flags & PLLM)
+ tegra3_pll_m_override_update(c, true);
}
static int tegra3_pll_clk_enable(struct clk *c)
@@ -1542,6 +1579,27 @@ static void tegra3_pll_clk_disable(struct clk *c)
}
}
+static int tegra3_pllm_override_rate(
+ struct clk *c, const struct clk_pll_freq_table *sel, u32 p_div)
+{
+ u32 val, old_base;
+
+ old_base = val = pmc_readl(PMC_PLLM_WB0_OVERRIDE);
+
+ /* Keep default CPCON and DCCON in override configuration */
+ val &= ~(PMC_PLLM_WB0_OVERRIDE_DIVM_MASK |
+ PMC_PLLM_WB0_OVERRIDE_DIVN_MASK |
+ PMC_PLLM_WB0_OVERRIDE_DIVP_MASK);
+ val |= (sel->m << PMC_PLLM_WB0_OVERRIDE_DIVM_SHIFT) |
+ (sel->n << PMC_PLLM_WB0_OVERRIDE_DIVN_SHIFT) |
+ (p_div << PMC_PLLM_WB0_OVERRIDE_DIVP_SHIFT);
+
+ if (val != old_base)
+ pmc_writel(val, PMC_PLLM_WB0_OVERRIDE);
+
+ return 0;
+}
+
static int tegra3_pll_clk_set_rate(struct clk *c, unsigned long rate)
{
u32 val, p_div, old_base;
@@ -1561,7 +1619,7 @@ static int tegra3_pll_clk_set_rate(struct clk *c, unsigned long rate)
return ret;
}
- if (c->flags & PLLM) {
+ if ((c->flags & PLLM) && (c->state == ON)) {
if (rate != clk_get_rate_locked(c)) {
pr_err("%s: Can not change memory %s rate in flight\n",
__func__, c->name);
@@ -1643,6 +1701,13 @@ static int tegra3_pll_clk_set_rate(struct clk *c, unsigned long rate)
c->mul = sel->n;
c->div = sel->m * sel->p;
+ if (c->flags & PLLM) {
+ val = pmc_readl(PMC_PLLP_WB0_OVERRIDE);
+ if (val & PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE)
+ return tegra3_pllm_override_rate(
+ c, sel, p_div >> PLL_BASE_DIVP_SHIFT);
+ }
+
old_base = val = clk_readl(c->reg + PLL_BASE);
val &= ~(PLL_BASE_DIVM_MASK | PLL_BASE_DIVN_MASK |
((c->flags & PLLU) ? PLLU_BASE_POST_DIV : PLL_BASE_DIVP_MASK));
@@ -1692,12 +1757,14 @@ static void tegra3_pllp_clk_init(struct clk *c)
tegra3_pllp_init_dependencies(c->u.pll.fixed_rate);
}
+#if defined(CONFIG_PM_SLEEP)
static void tegra3_pllp_clk_resume(struct clk *c)
{
unsigned long rate = c->u.pll.fixed_rate;
tegra3_pll_clk_init(c);
BUG_ON(rate != c->u.pll.fixed_rate);
}
+#endif
static struct clk_ops tegra_pllp_ops = {
.init = tegra3_pllp_clk_init,
@@ -2571,8 +2638,15 @@ static int tegra3_emc_clk_set_rate(struct clk *c, unsigned long rate)
* to achieve requested rate. */
p = tegra_emc_predict_parent(rate, &div_value);
div_value += 2; /* emc has fractional DIV_U71 divider */
+
+ /* No matching rate in emc dfs table */
+ if (IS_ERR(p))
+ return PTR_ERR(p);
+
+ /* Table rate found, but need to relock source pll */
if (!p)
- return -EINVAL;
+ return tegra3_emc_relock_set_rate(c, clk_get_rate_locked(c),
+ rate, rate * (div_value / 2));
if (p == c->parent) {
if (div_value == c->div)
@@ -2775,6 +2849,9 @@ static void tegra3_clk_cbus_init(struct clk *c)
{
c->state = OFF;
c->set = true;
+ c->shared_bus_backup.bus_rate =
+ clk_get_rate(c->shared_bus_backup.input) /
+ c->shared_bus_backup.value;
}
static int tegra3_clk_cbus_enable(struct clk *c)
@@ -3011,7 +3088,8 @@ static int tegra3_clk_shared_bus_update(struct clk *bus)
(c->u.shared_bus_user.mode == SHARED_CEILING)) {
switch (c->u.shared_bus_user.mode) {
case SHARED_BW:
- bw += c->u.shared_bus_user.rate;
+ if (bw < bus->max_rate)
+ bw += c->u.shared_bus_user.rate;
break;
case SHARED_CEILING:
ceiling = min(c->u.shared_bus_user.rate,
@@ -3024,6 +3102,16 @@ static int tegra3_clk_shared_bus_update(struct clk *bus)
}
}
}
+
+ if (bw) {
+ if (bus->flags & PERIPH_EMC_ENB) {
+ bw = tegra_emc_bw_efficiency ?
+ (bw / tegra_emc_bw_efficiency) : bus->max_rate;
+ bw = (bw < bus->max_rate / 100) ?
+ (bw * 100) : bus->max_rate;
+ }
+ bw = clk_round_rate_locked(bus, bw);
+ }
rate = min(max(rate, bw), ceiling);
old_rate = clk_get_rate_locked(bus);
@@ -3072,6 +3160,10 @@ static long tegra_clk_shared_bus_round_rate(struct clk *c, unsigned long rate)
if (c->u.shared_bus_user.mode == SHARED_AUTO)
rate = 0;
+ /* BW users should not be rounded until aggregated */
+ if (c->u.shared_bus_user.mode == SHARED_BW)
+ return rate;
+
return clk_round_rate(c->parent, rate);
}
@@ -3993,7 +4085,7 @@ static struct clk_mux_sel mux_pllm_pllc_pllp_plla[] = {
static struct clk_mux_sel mux_pllm_pllc_pllp_clkm[] = {
{ .input = &tegra_pll_m, .value = 0},
- /* { .input = &tegra_pll_c, .value = 1}, not used on tegra3 */
+ { .input = &tegra_pll_c, .value = 1},
{ .input = &tegra_pll_p, .value = 2},
{ .input = &tegra_clk_m, .value = 3},
{ 0, 0},
@@ -4117,6 +4209,9 @@ static struct clk tegra_clk_emc = {
.u.periph = {
.clk_num = 57,
},
+ .shared_bus_backup = {
+ .input = &tegra_pll_c,
+ },
.rate_change_nh = &emc_rate_change_nh,
};
@@ -4233,6 +4328,7 @@ struct clk tegra_list_clks[] = {
PERIPH_CLK("vcp", "tegra-avp", "vcp", 29, 0, 250000000, mux_clk_m, 0),
PERIPH_CLK("bsea", "tegra-avp", "bsea", 62, 0, 250000000, mux_clk_m, 0),
PERIPH_CLK("bsev", "tegra-aes", "bsev", 63, 0, 250000000, mux_clk_m, 0),
+ PERIPH_CLK("cec", "tegra_cec", NULL, 136, 0, 26000000, mux_clk_m, PERIPH_ON_APB),
PERIPH_CLK("vde", "vde", NULL, 61, 0x1c8, 600000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_INT),
PERIPH_CLK("csite", "csite", NULL, 73, 0x1d4, 144000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* max rate ??? */
PERIPH_CLK("la", "la", NULL, 76, 0x1f8, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
@@ -4274,11 +4370,13 @@ struct clk tegra_list_clks[] = {
PERIPH_CLK("tvdac", "tvdac", NULL, 53, 0x194, 220000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */
PERIPH_CLK("disp1", "tegradc.0", NULL, 27, 0x138, 600000000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm, MUX | MUX8),
PERIPH_CLK("disp2", "tegradc.1", NULL, 26, 0x13c, 600000000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm, MUX | MUX8),
- PERIPH_CLK("usbd", "fsl-tegra-udc", NULL, 22, 0, 480000000, mux_clk_m, 0), /* requires min voltage */
+ PERIPH_CLK("usbd", "tegra-udc.0", NULL, 22, 0, 480000000, mux_clk_m, 0), /* requires min voltage */
PERIPH_CLK("usb2", "tegra-ehci.1", NULL, 58, 0, 480000000, mux_clk_m, 0), /* requires min voltage */
PERIPH_CLK("usb3", "tegra-ehci.2", NULL, 59, 0, 480000000, mux_clk_m, 0), /* requires min voltage */
PERIPH_CLK("dsia", "tegradc.0", "dsia", 48, 0, 500000000, mux_plld_out0, 0),
PERIPH_CLK_EX("dsib", "tegradc.1", "dsib", 82, 0xd0, 500000000, mux_plld_out0_plld2_out0, MUX | PLLD, &tegra_dsib_clk_ops),
+ PERIPH_CLK("dsi1-fixed", "tegradc.0", "dsi-fixed", 0, 0, 108000000, mux_pllp_out3, PERIPH_NO_ENB),
+ PERIPH_CLK("dsi2-fixed", "tegradc.1", "dsi-fixed", 0, 0, 108000000, mux_pllp_out3, PERIPH_NO_ENB),
PERIPH_CLK("csi", "tegra_camera", "csi", 52, 0, 102000000, mux_pllp_out3, 0),
PERIPH_CLK("isp", "tegra_camera", "isp", 23, 0, 150000000, mux_clk_m, 0), /* same frequency as VI */
PERIPH_CLK("csus", "tegra_camera", "csus", 92, 0, 150000000, mux_clk_m, PERIPH_NO_RESET),
@@ -4296,7 +4394,7 @@ struct clk tegra_list_clks[] = {
SHARED_CLK("avp.sclk", "tegra-avp", "sclk", &tegra_clk_sbus_cmplx, NULL, 0, 0),
SHARED_CLK("bsea.sclk", "tegra-aes", "sclk", &tegra_clk_sbus_cmplx, NULL, 0, 0),
- SHARED_CLK("usbd.sclk", "fsl-tegra-udc", "sclk", &tegra_clk_sbus_cmplx, NULL, 0, 0),
+ SHARED_CLK("usbd.sclk", "tegra-udc.0", "sclk", &tegra_clk_sbus_cmplx, NULL, 0, 0),
SHARED_CLK("usb1.sclk", "tegra-ehci.0", "sclk", &tegra_clk_sbus_cmplx, NULL, 0, 0),
SHARED_CLK("usb2.sclk", "tegra-ehci.1", "sclk", &tegra_clk_sbus_cmplx, NULL, 0, 0),
SHARED_CLK("usb3.sclk", "tegra-ehci.2", "sclk", &tegra_clk_sbus_cmplx, NULL, 0, 0),
@@ -4316,7 +4414,7 @@ struct clk tegra_list_clks[] = {
SHARED_CLK("disp1.emc", "tegradc.0", "emc", &tegra_clk_emc, NULL, 0, SHARED_BW),
SHARED_CLK("disp2.emc", "tegradc.1", "emc", &tegra_clk_emc, NULL, 0, SHARED_BW),
SHARED_CLK("hdmi.emc", "hdmi", "emc", &tegra_clk_emc, NULL, 0, 0),
- SHARED_CLK("usbd.emc", "fsl-tegra-udc", "emc", &tegra_clk_emc, NULL, 0, 0),
+ SHARED_CLK("usbd.emc", "tegra-udc.0", "emc", &tegra_clk_emc, NULL, 0, 0),
SHARED_CLK("usb1.emc", "tegra-ehci.0", "emc", &tegra_clk_emc, NULL, 0, 0),
SHARED_CLK("usb2.emc", "tegra-ehci.1", "emc", &tegra_clk_emc, NULL, 0, 0),
SHARED_CLK("usb3.emc", "tegra-ehci.2", "emc", &tegra_clk_emc, NULL, 0, 0),
@@ -4325,7 +4423,8 @@ struct clk tegra_list_clks[] = {
SHARED_CLK("3d.emc", "tegra_gr3d", "emc", &tegra_clk_emc, NULL, 0, 0),
SHARED_CLK("2d.emc", "tegra_gr2d", "emc", &tegra_clk_emc, NULL, 0, 0),
SHARED_CLK("mpe.emc", "tegra_mpe", "emc", &tegra_clk_emc, NULL, 0, 0),
- SHARED_CLK("camera.emc", "tegra_camera", "emc", &tegra_clk_emc, NULL, 0, 0),
+ SHARED_CLK("camera.emc", "tegra_camera", "emc", &tegra_clk_emc, NULL, 0, SHARED_BW),
+ SHARED_CLK("sdmmc4.emc", "sdhci-tegra.3", "emc", &tegra_clk_emc, NULL, 0, 0),
SHARED_CLK("floor.emc", "floor.emc", NULL, &tegra_clk_emc, NULL, 0, 0),
SHARED_CLK("host1x.cbus", "tegra_host1x", "host1x", &tegra_clk_cbus, "host1x", 2, SHARED_AUTO),
@@ -4391,6 +4490,7 @@ struct clk_duplicate tegra_clk_duplicates[] = {
CLK_DUPLICATE("avp.sclk", "nvavp", "sclk"),
CLK_DUPLICATE("avp.emc", "nvavp", "emc"),
CLK_DUPLICATE("vde.cbus", "nvavp", "vde"),
+ CLK_DUPLICATE("epp.cbus", "tegra_isp", "epp"),
};
struct clk *tegra_ptr_clks[] = {
@@ -4438,6 +4538,86 @@ struct clk *tegra_ptr_clks[] = {
&tegra_clk_cbus,
};
+static int tegra3_emc_relock_set_rate(struct clk *emc, unsigned long old_rate,
+ unsigned long new_rate, unsigned long new_pll_rate)
+{
+ int ret;
+
+ struct clk *sbus = &tegra_clk_sbus_cmplx;
+ struct clk *cbus = &tegra_clk_cbus;
+ struct clk *pll_m = &tegra_pll_m;
+ unsigned long backup_rate = emc->shared_bus_backup.bus_rate;
+ unsigned long flags;
+
+ bool on_pllm = emc->parent == pll_m;
+
+ /*
+ * Relock procedure pre-conditions:
+ * - LPDDR2 only
+ * - EMC clock is enabled, and EMC backup rate is found in DFS table
+ * - All 3 shared buses: emc, sbus, cbus can sleep
+ */
+ if ((tegra_emc_get_dram_type() != DRAM_TYPE_LPDDR2) || !emc->refcnt ||
+ !backup_rate || (cbus->parent != emc->shared_bus_backup.input) ||
+ !clk_cansleep(emc) || !clk_cansleep(cbus) || !clk_cansleep(sbus))
+ return -ENOSYS;
+
+ /* Move sbus from PLLM by setting it at low rate threshold level */
+ clk_lock_save(sbus, &flags);
+ if (clk_get_rate_locked(sbus) > sbus->u.system.threshold) {
+ ret = clk_set_rate_locked(sbus, sbus->u.system.threshold);
+ if (ret)
+ goto _sbus_out;
+ }
+
+ /* If PLLM is current EMC parent set cbus to backup rate, and move EMC
+ to backup PLLC */
+ if (on_pllm) {
+ clk_lock_save(cbus, &flags);
+ clk_enable(cbus->parent);
+ ret = clk_set_rate_locked(cbus, backup_rate);
+ if (ret) {
+ clk_disable(cbus->parent);
+ goto _cbus_out;
+ }
+
+ ret = tegra_emc_backup(backup_rate);
+ if (ret) {
+ clk_disable(cbus->parent);
+ goto _cbus_out;
+ }
+ clk_disable(emc->parent);
+ clk_reparent(emc, cbus->parent);
+ }
+
+ /*
+ * Re-lock PLLM and switch EMC to it; relocking error indicates that
+ * PLLM has some other than EMC or sbus client. In this case PLLM has
+ * not been changed, and we still can safely switch back. Recursive
+ * tegra3_emc_clk_set_rate() call below will be resolved, since PLLM
+ * is now matching target rate.
+ */
+ ret = clk_set_rate(pll_m, new_pll_rate);
+ if (ret) {
+ if (on_pllm)
+ tegra3_emc_clk_set_rate(emc, old_rate);
+ } else
+ ret = tegra3_emc_clk_set_rate(emc, new_rate);
+
+
+_cbus_out:
+ if (on_pllm) {
+ tegra3_clk_shared_bus_update(cbus);
+ clk_unlock_restore(cbus, &flags);
+ }
+
+_sbus_out:
+ tegra3_clk_shared_bus_update(sbus);
+ clk_unlock_restore(sbus, &flags);
+
+ return ret;
+}
+
/*
* Backup rate targets for each CPU mode is selected below Fmax(Vmin), and
* high enough to avoid voltage droop when CPU clock is switched between
@@ -4620,13 +4800,14 @@ static struct cpufreq_frequency_table freq_table_1p7GHz[] = {
{ 5, 620000 },
{ 6, 760000 },
{ 7, 910000 },
- { 8, 1150000 },
- { 9, 1300000 },
- {10, 1400000 },
- {11, 1500000 },
- {12, 1600000 },
- {13, 1700000 },
- {14, CPUFREQ_TABLE_END },
+ { 8, 1000000 },
+ { 9, 1150000 },
+ {10, 1300000 },
+ {11, 1400000 },
+ {12, 1500000 },
+ {13, 1600000 },
+ {14, 1700000 },
+ {15, CPUFREQ_TABLE_END },
};
static struct tegra_cpufreq_table_data cpufreq_tables[] = {
@@ -4727,10 +4908,10 @@ unsigned long tegra_emc_to_cpu_ratio(unsigned long cpu_rate)
/* Vote on memory bus frequency based on cpu frequency;
cpu rate is in kHz, emc rate is in Hz */
- if (cpu_rate >= 750000)
- return emc_max_rate; /* cpu >= 750 MHz, emc max */
+ if (cpu_rate >= 925000)
+ return emc_max_rate; /* cpu >= 925 MHz, emc max */
else if (cpu_rate >= 450000)
- return emc_max_rate/2; /* cpu >= 500 MHz, emc max/2 */
+ return emc_max_rate/2; /* cpu >= 450 MHz, emc max/2 */
else if (cpu_rate >= 250000)
return 100000000; /* cpu >= 250 MHz, emc 100 MHz */
else
@@ -4963,6 +5144,7 @@ static void tegra_clk_resume(void)
/* Since EMC clock is not restored, and may not preserve parent across
suspend, update current state, and mark EMC DFS as out of sync */
+ tegra3_pll_m_override_update(&tegra_pll_m, false);
p = tegra_clk_emc.parent;
tegra3_periph_clk_init(&tegra_clk_emc);
@@ -5003,9 +5185,17 @@ static struct syscore_ops tegra_clk_syscore_ops = {
#define CLK_RSTENB_DEV_V_0_DAM1_BIT (1 << 13)
#define CLK_RSTENB_DEV_V_0_DAM0_BIT (1 << 12)
#define CLK_RSTENB_DEV_V_0_AUDIO_BIT (1 << 10)
+#define CLK_RSTENB_DEV_V_0_3D2_BIT (1 << 2)
#define CLK_RSTENB_DEV_L_0_HOST1X_BIT (1 << 28)
#define CLK_RSTENB_DEV_L_0_DISP1_BIT (1 << 27)
+#define CLK_RSTENB_DEV_L_0_3D_BIT (1 << 24)
+#define CLK_RSTENB_DEV_L_0_2D_BIT (1 << 21)
+#define CLK_RSTENB_DEV_L_0_VI_BIT (1 << 20)
+#define CLK_RSTENB_DEV_L_0_EPP_BIT (1 << 19)
+
+#define CLK_RSTENB_DEV_H_0_VDE_BIT (1 << 29)
+#define CLK_RSTENB_DEV_H_0_MPE_BIT (1 << 28)
#define DISP1_CLK_REG_OFFSET 0x138
#define DISP1_CLK_SRC_SHIFT 29
@@ -5052,6 +5242,31 @@ static struct syscore_ops tegra_clk_syscore_ops = {
#define AUDIO_CLK_DIV_DEFAULT (\
(0 << AUDIO_CLK_DIV_SHIFT))
+#define VCLK_SRC_SHIFT 30
+#define VCLK_SRC_MASK (0x3 << VCLK_SRC_SHIFT)
+#define VCLK_SRC_PLLM_OUT0 0
+#define VCLK_SRC_PLLC_OUT0 1
+#define VCLK_SRC_PLLP_OUT0 2
+#define VCLK_SRC_PLLA_OUT0 3
+#define VCLK_SRC_DEFAULT (VCLK_SRC_PLLM_OUT0 << VCLK_SRC_SHIFT)
+#define VCLK_IDLE_DIV_SHIFT 8
+#define VCLK_IDLE_DIV_MASK (0xff << VCLK_IDLE_DIV_SHIFT)
+#define VCLK_IDLE_DIV_DEFAULT (0 << VCLK_IDLE_DIV_SHIFT)
+#define VCLK_DIV_SHIFT 0
+#define VCLK_DIV_MASK (0xff << VCLK_DIV_SHIFT)
+#define VCLK_DIV_DEFAULT (0xa << VCLK_DIV_SHIFT)
+
+#define VI_CLK_REG_OFFSET 0x148
+#define VI_CLK_SEL_VI_SENSOR_CLK (1 << 25)
+#define VI_CLK_SEL_EXTERNAL_CLK (1 << 24)
+#define VI_SENSOR_CLK_REG_OFFSET 0x1a8
+#define G3D_CLK_REG_OFFSET 0x158
+#define G2D_CLK_REG_OFFSET 0x15c
+#define EPP_CLK_REG_OFFSET 0x16c
+#define MPE_CLK_REG_OFFSET 0x170
+#define VDE_CLK_REG_OFFSET 0x170
+#define G3D2_CLK_REG_OFFSET 0x3b0
+
static void __init clk_setbit(u32 reg, u32 bit)
{
u32 val = clk_readl(reg);
@@ -5086,6 +5301,43 @@ static void __init clk_setbits(u32 reg, u32 bits, u32 mask)
udelay(2);
}
+static void __init vclk_init(int tag, u32 src, u32 rebit)
+{
+ u32 rst, enb;
+
+ switch (tag) {
+ case 'L':
+ rst = RST_DEVICES_L;
+ enb = CLK_OUT_ENB_L;
+ break;
+ case 'H':
+ rst = RST_DEVICES_H;
+ enb = CLK_OUT_ENB_H;
+ break;
+ case 'U':
+ rst = RST_DEVICES_U;
+ enb = CLK_OUT_ENB_U;
+ break;
+ case 'V':
+ rst = RST_DEVICES_V;
+ enb = CLK_OUT_ENB_V;
+ break;
+ case 'W':
+ rst = RST_DEVICES_W;
+ enb = CLK_OUT_ENB_W;
+ break;
+ default:
+ /* Quietly ignore. */
+ return;
+ }
+
+ clk_setbit(rst, rebit);
+ clk_clrbit(enb, rebit);
+ clk_setbits(src, VCLK_SRC_DEFAULT, VCLK_SRC_MASK);
+ clk_setbits(src, VCLK_DIV_DEFAULT, VCLK_DIV_MASK);
+ clk_clrbit(rst, rebit);
+}
+
static int __init tegra_soc_preinit_clocks(void)
{
/*
@@ -5161,6 +5413,15 @@ static int __init tegra_soc_preinit_clocks(void)
AUDIO_CLK_SRC_DEFAULT, AUDIO_CLK_SRC_MASK);
clk_clrbit(RST_DEVICES_V, CLK_RSTENB_DEV_V_0_AUDIO_BIT);
+ /* Pre-initialize Video clocks. */
+ vclk_init('L', G3D_CLK_REG_OFFSET, CLK_RSTENB_DEV_L_0_3D_BIT);
+ vclk_init('L', G2D_CLK_REG_OFFSET, CLK_RSTENB_DEV_L_0_2D_BIT);
+ vclk_init('L', VI_CLK_REG_OFFSET, CLK_RSTENB_DEV_L_0_VI_BIT);
+ vclk_init('L', EPP_CLK_REG_OFFSET, CLK_RSTENB_DEV_L_0_EPP_BIT);
+ vclk_init('H', VDE_CLK_REG_OFFSET, CLK_RSTENB_DEV_H_0_VDE_BIT);
+ vclk_init('H', MPE_CLK_REG_OFFSET, CLK_RSTENB_DEV_H_0_MPE_BIT);
+ vclk_init('V', G3D2_CLK_REG_OFFSET, CLK_RSTENB_DEV_V_0_3D2_BIT);
+
return 0;
}
#endif /* CONFIG_TEGRA_PREINIT_CLOCKS */
diff --git a/arch/arm/mach-tegra/tegra3_dvfs.c b/arch/arm/mach-tegra/tegra3_dvfs.c
index dcda3f3cae3b..5af1b44cd99c 100644
--- a/arch/arm/mach-tegra/tegra3_dvfs.c
+++ b/arch/arm/mach-tegra/tegra3_dvfs.c
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/tegra3_dvfs.c
*
- * Copyright (C) 2010-2011 NVIDIA Corporation.
+ * 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
@@ -33,10 +33,10 @@ static bool tegra_dvfs_core_disabled;
static struct dvfs *cpu_dvfs;
static const int cpu_millivolts[MAX_DVFS_FREQS] = {
- 800, 825, 850, 875, 900, 912, 975, 1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175, 1200, 1212, 1237};
+ 800, 825, 850, 875, 900, 916, 950, 975, 1000, 1007, 1025, 1050, 1075, 1100, 1125, 1150, 1175, 1200, 1212, 1237};
static const unsigned int cpu_cold_offs_mhz[MAX_DVFS_FREQS] = {
- 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50};
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50};
static const int core_millivolts[MAX_DVFS_FREQS] = {
950, 1000, 1050, 1100, 1150, 1200, 1250, 1300, 1350};
@@ -141,57 +141,59 @@ static struct dvfs_relationship tegra3_dvfs_relationships[] = {
}
static struct dvfs cpu_dvfs_table[] = {
- /* Cpu voltages (mV): 800, 825, 850, 875, 900, 912, 975, 1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175, 1200, 1212, 1237 */
- CPU_DVFS("cpu_g", 0, 0, MHZ, 1, 1, 684, 684, 817, 817, 1026, 1102, 1149, 1187, 1225, 1282, 1300),
- CPU_DVFS("cpu_g", 0, 1, MHZ, 1, 1, 807, 807, 948, 948, 1117, 1171, 1206, 1300),
- CPU_DVFS("cpu_g", 0, 2, MHZ, 1, 1, 883, 883, 1039, 1039, 1178, 1206, 1300),
- CPU_DVFS("cpu_g", 0, 3, MHZ, 1, 1, 931, 931, 1102, 1102, 1216, 1300),
-
- CPU_DVFS("cpu_g", 1, 0, MHZ, 460, 460, 550, 550, 680, 680, 820, 970, 1040, 1080, 1150, 1200, 1280, 1300),
- CPU_DVFS("cpu_g", 1, 1, MHZ, 480, 480, 650, 650, 780, 780, 990, 1040, 1100, 1200, 1300),
- CPU_DVFS("cpu_g", 1, 2, MHZ, 520, 520, 700, 700, 860, 860, 1050, 1150, 1200, 1300),
- CPU_DVFS("cpu_g", 1, 3, MHZ, 550, 550, 770, 770, 910, 910, 1150, 1230, 1300),
-
- CPU_DVFS("cpu_g", 2, 1, MHZ, 480, 480, 650, 650, 780, 780, 990, 1040, 1100, 1200, 1250, 1300, 1330, 1400),
- CPU_DVFS("cpu_g", 2, 2, MHZ, 520, 520, 700, 700, 860, 860, 1050, 1150, 1200, 1280, 1300, 1350, 1400),
- CPU_DVFS("cpu_g", 2, 3, MHZ, 550, 550, 770, 770, 910, 910, 1150, 1230, 1280, 1300, 1350, 1400),
-
- CPU_DVFS("cpu_g", 3, 1, MHZ, 480, 480, 650, 650, 780, 780, 990, 1040, 1100, 1200, 1250, 1300, 1330, 1400),
- CPU_DVFS("cpu_g", 3, 2, MHZ, 520, 520, 700, 700, 860, 860, 1050, 1150, 1200, 1280, 1300, 1350, 1400),
- CPU_DVFS("cpu_g", 3, 3, MHZ, 550, 550, 770, 770, 910, 910, 1150, 1230, 1280, 1300, 1350, 1400),
-
- CPU_DVFS("cpu_g", 4, 0, MHZ, 460, 460, 550, 550, 680, 680, 820, 970, 1040, 1080, 1150, 1200, 1240, 1280, 1320, 1360, 1360, 1500),
- CPU_DVFS("cpu_g", 4, 1, MHZ, 480, 480, 650, 650, 780, 780, 990, 1040, 1100, 1200, 1250, 1300, 1330, 1360, 1400, 1500),
- CPU_DVFS("cpu_g", 4, 2, MHZ, 520, 520, 700, 700, 860, 860, 1050, 1150, 1200, 1280, 1300, 1340, 1380, 1500),
- CPU_DVFS("cpu_g", 4, 3, MHZ, 550, 550, 770, 770, 910, 910, 1150, 1230, 1280, 1330, 1370, 1400, 1500),
-
- CPU_DVFS("cpu_g", 5, 3, MHZ, 550, 550, 770, 770, 910, 910, 1150, 1230, 1280, 1330, 1370, 1400, 1470, 1500, 1500, 1540, 1540, 1700),
- CPU_DVFS("cpu_g", 5, 4, MHZ, 550, 550, 770, 770, 940, 940, 1160, 1240, 1280, 1360, 1390, 1470, 1500, 1520, 1520, 1590, 1700),
-
- CPU_DVFS("cpu_g", 6, 3, MHZ, 550, 550, 770, 770, 910, 910, 1150, 1230, 1280, 1330, 1370, 1400, 1470, 1500, 1500, 1540, 1540, 1700),
- CPU_DVFS("cpu_g", 6, 4, MHZ, 550, 550, 770, 770, 940, 940, 1160, 1240, 1280, 1360, 1390, 1470, 1500, 1520, 1520, 1590, 1700),
-
- CPU_DVFS("cpu_g", 7, 0, MHZ, 460, 460, 550, 550, 680, 680, 820, 970, 1040, 1080, 1150, 1200, 1280, 1300),
- CPU_DVFS("cpu_g", 7, 1, MHZ, 480, 480, 650, 650, 780, 780, 990, 1040, 1100, 1200, 1300),
- CPU_DVFS("cpu_g", 7, 2, MHZ, 520, 520, 700, 700, 860, 860, 1050, 1150, 1200, 1300),
- CPU_DVFS("cpu_g", 7, 3, MHZ, 550, 550, 770, 770, 910, 910, 1150, 1230, 1300),
- CPU_DVFS("cpu_g", 7, 4, MHZ, 550, 550, 770, 770, 940, 940, 1160, 1300),
-
- CPU_DVFS("cpu_g", 8, 0, MHZ, 460, 460, 550, 550, 680, 680, 820, 970, 1040, 1080, 1150, 1200, 1280, 1300),
- CPU_DVFS("cpu_g", 8, 1, MHZ, 480, 480, 650, 650, 780, 780, 990, 1040, 1100, 1200, 1300),
- CPU_DVFS("cpu_g", 8, 2, MHZ, 520, 520, 700, 700, 860, 860, 1050, 1150, 1200, 1300),
- CPU_DVFS("cpu_g", 8, 3, MHZ, 550, 550, 770, 770, 910, 910, 1150, 1230, 1300),
- CPU_DVFS("cpu_g", 8, 4, MHZ, 550, 550, 770, 770, 940, 940, 1160, 1300),
-
- CPU_DVFS("cpu_g", 9, -1, MHZ, 1, 1, 1, 1, 1, 900, 900, 900, 900, 900, 900, 900, 900, 900),
- CPU_DVFS("cpu_g", 10, -1, MHZ, 1, 1, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900),
- CPU_DVFS("cpu_g", 11, -1, MHZ, 1, 1, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600),
-
- CPU_DVFS("cpu_g", 12, 3, MHZ, 550, 550, 770, 770, 910, 910, 1150, 1230, 1280, 1330, 1370, 1400, 1470, 1500, 1500, 1540, 1540, 1700),
- CPU_DVFS("cpu_g", 12, 4, MHZ, 550, 550, 770, 770, 940, 940, 1160, 1240, 1280, 1360, 1390, 1470, 1500, 1520, 1520, 1590, 1700),
-
- CPU_DVFS("cpu_g", 13, 3, MHZ, 550, 550, 770, 770, 910, 910, 1150, 1230, 1280, 1330, 1370, 1400, 1470, 1500, 1500, 1540, 1540, 1700),
- CPU_DVFS("cpu_g", 13, 4, MHZ, 550, 550, 770, 770, 940, 940, 1160, 1240, 1280, 1360, 1390, 1470, 1500, 1520, 1520, 1590, 1700),
+ /* Cpu voltages (mV): 800, 825, 850, 875, 900, 916, 950, 975, 1000, 1007, 1025, 1050, 1075, 1100, 1125, 1150, 1175, 1200, 1212, 1237 */
+ CPU_DVFS("cpu_g", 0, 0, MHZ, 1, 1, 684, 684, 817, 817, 817, 1026, 1102, 1102, 1149, 1187, 1225, 1282, 1300),
+ CPU_DVFS("cpu_g", 0, 1, MHZ, 1, 1, 807, 807, 948, 948, 948, 1117, 1171, 1171, 1206, 1300),
+ CPU_DVFS("cpu_g", 0, 2, MHZ, 1, 1, 883, 883, 1039, 1039, 1039, 1178, 1206, 1206, 1300),
+ CPU_DVFS("cpu_g", 0, 3, MHZ, 1, 1, 931, 931, 1102, 1102, 1102, 1216, 1300, 1300),
+
+ CPU_DVFS("cpu_g", 1, 0, MHZ, 460, 460, 550, 550, 680, 680, 680, 820, 970, 970, 1040, 1080, 1150, 1200, 1280, 1300),
+ CPU_DVFS("cpu_g", 1, 1, MHZ, 480, 480, 650, 650, 780, 780, 780, 990, 1040, 1040, 1100, 1200, 1300),
+ CPU_DVFS("cpu_g", 1, 2, MHZ, 520, 520, 700, 700, 860, 860, 860, 1050, 1150, 1150, 1200, 1300),
+ CPU_DVFS("cpu_g", 1, 3, MHZ, 550, 550, 770, 770, 910, 910, 910, 1150, 1230, 1230, 1300),
+
+ CPU_DVFS("cpu_g", 2, 1, MHZ, 480, 480, 650, 650, 780, 780, 780, 990, 1040, 1040, 1100, 1200, 1250, 1300, 1330, 1400),
+ CPU_DVFS("cpu_g", 2, 2, MHZ, 520, 520, 700, 700, 860, 860, 860, 1050, 1150, 1150, 1200, 1280, 1300, 1350, 1400),
+ CPU_DVFS("cpu_g", 2, 3, MHZ, 550, 550, 770, 770, 910, 910, 910, 1150, 1230, 1230, 1280, 1300, 1350, 1400),
+
+ CPU_DVFS("cpu_g", 3, 1, MHZ, 480, 480, 650, 650, 780, 780, 780, 990, 1040, 1040, 1100, 1200, 1250, 1300, 1330, 1400),
+ CPU_DVFS("cpu_g", 3, 2, MHZ, 520, 520, 700, 700, 860, 860, 860, 1050, 1150, 1150, 1200, 1280, 1300, 1350, 1400),
+ CPU_DVFS("cpu_g", 3, 3, MHZ, 550, 550, 770, 770, 910, 910, 910, 1150, 1230, 1230, 1280, 1300, 1350, 1400),
+
+ CPU_DVFS("cpu_g", 4, 0, MHZ, 460, 460, 550, 550, 680, 680, 680, 820, 970, 970, 1040, 1080, 1150, 1200, 1240, 1280, 1320, 1360, 1360, 1500),
+ CPU_DVFS("cpu_g", 4, 1, MHZ, 480, 480, 650, 650, 780, 780, 780, 990, 1040, 1040, 1100, 1200, 1250, 1300, 1330, 1360, 1400, 1500),
+ CPU_DVFS("cpu_g", 4, 2, MHZ, 520, 520, 700, 700, 860, 860, 860, 1050, 1150, 1150, 1200, 1280, 1300, 1340, 1380, 1500),
+ CPU_DVFS("cpu_g", 4, 3, MHZ, 550, 550, 770, 770, 910, 910, 910, 1150, 1230, 1230, 1280, 1330, 1370, 1400, 1500),
+
+ CPU_DVFS("cpu_g", 5, 3, MHZ, 550, 550, 770, 770, 910, 910, 910, 1150, 1230, 1230, 1280, 1330, 1370, 1400, 1470, 1500, 1500, 1540, 1540, 1700),
+ CPU_DVFS("cpu_g", 5, 4, MHZ, 550, 550, 770, 770, 940, 940, 940, 1160, 1240, 1240, 1280, 1360, 1390, 1470, 1500, 1520, 1520, 1590, 1700),
+
+ CPU_DVFS("cpu_g", 6, 3, MHZ, 550, 550, 770, 770, 910, 910, 910, 1150, 1230, 1230, 1280, 1330, 1370, 1400, 1470, 1500, 1500, 1540, 1540, 1700),
+ CPU_DVFS("cpu_g", 6, 4, MHZ, 550, 550, 770, 770, 940, 940, 940, 1160, 1240, 1240, 1280, 1360, 1390, 1470, 1500, 1520, 1520, 1590, 1700),
+
+ CPU_DVFS("cpu_g", 7, 0, MHZ, 460, 460, 550, 550, 680, 680, 680, 820, 970, 970, 1040, 1080, 1150, 1200, 1280, 1300),
+ CPU_DVFS("cpu_g", 7, 1, MHZ, 480, 480, 650, 650, 780, 780, 780, 990, 1040, 1040, 1100, 1200, 1300),
+ CPU_DVFS("cpu_g", 7, 2, MHZ, 520, 520, 700, 700, 860, 860, 860, 1050, 1150, 1150, 1200, 1300),
+ CPU_DVFS("cpu_g", 7, 3, MHZ, 550, 550, 770, 770, 910, 910, 910, 1150, 1230, 1230, 1300),
+ CPU_DVFS("cpu_g", 7, 4, MHZ, 550, 550, 770, 770, 940, 940, 940, 1160, 1300, 1300),
+
+ CPU_DVFS("cpu_g", 8, 0, MHZ, 460, 460, 550, 550, 680, 680, 680, 820, 970, 970, 1040, 1080, 1150, 1200, 1280, 1300),
+ CPU_DVFS("cpu_g", 8, 1, MHZ, 480, 480, 650, 650, 780, 780, 780, 990, 1040, 1040, 1100, 1200, 1300),
+ CPU_DVFS("cpu_g", 8, 2, MHZ, 520, 520, 700, 700, 860, 860, 860, 1050, 1150, 1150, 1200, 1300),
+ CPU_DVFS("cpu_g", 8, 3, MHZ, 550, 550, 770, 770, 910, 910, 910, 1150, 1230, 1230, 1300),
+ CPU_DVFS("cpu_g", 8, 4, MHZ, 550, 550, 770, 770, 940, 940, 940, 1160, 1300, 1300),
+
+ CPU_DVFS("cpu_g", 9, -1, MHZ, 1, 1, 1, 1, 1, 1, 1, 1, 1, 900, 900, 900, 900, 900, 900, 900),
+ CPU_DVFS("cpu_g", 10, -1, MHZ, 1, 1, 1, 1, 1, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900),
+ CPU_DVFS("cpu_g", 11, -1, MHZ, 1, 1, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600),
+ CPU_DVFS("cpu_g", 14, -1, MHZ, 1, 1, 1, 1, 1, 1, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900),
+ CPU_DVFS("cpu_g", 15, -1, MHZ, 1, 1, 1, 1, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900),
+
+ CPU_DVFS("cpu_g", 12, 3, MHZ, 550, 550, 770, 770, 910, 910, 910, 1150, 1230, 1230, 1280, 1330, 1370, 1400, 1470, 1500, 1500, 1540, 1540, 1700),
+ CPU_DVFS("cpu_g", 12, 4, MHZ, 550, 550, 770, 770, 940, 940, 940, 1160, 1240, 1240, 1280, 1360, 1390, 1470, 1500, 1520, 1520, 1590, 1700),
+
+ CPU_DVFS("cpu_g", 13, 3, MHZ, 550, 550, 770, 770, 910, 910, 910, 1150, 1230, 1230, 1280, 1330, 1370, 1400, 1470, 1500, 1500, 1540, 1540, 1700),
+ CPU_DVFS("cpu_g", 13, 4, MHZ, 550, 550, 770, 770, 940, 940, 940, 1160, 1240, 1240, 1280, 1360, 1390, 1470, 1500, 1520, 1520, 1590, 1700),
/*
* "Safe entry" to be used when no match for chip speedo, process
@@ -200,6 +202,10 @@ static struct dvfs cpu_dvfs_table[] = {
CPU_DVFS("cpu_g", -1, -1, MHZ, 1, 1, 216, 216, 300),
};
+static struct dvfs cpu_0_dvfs_table[] = {
+ /* Cpu voltages (mV): 800, 825, 850, 875, 900, 916, 950, 975, 1000, 1007, 1025, 1050, 1075, 1100, 1125, 1150, 1175, 1200, 1212, 1237 */
+};
+
#define CORE_DVFS(_clk_name, _speedo_id, _auto, _mult, _freqs...) \
{ \
.clk_name = _clk_name, \
@@ -222,13 +228,13 @@ static struct dvfs core_dvfs_table[] = {
CORE_DVFS("emc", 0, 1, KHZ, 1, 266500, 266500, 266500, 266500, 533000, 533000, 533000, 533000),
CORE_DVFS("emc", 1, 1, KHZ, 102000, 408000, 408000, 408000, 408000, 667000, 667000, 667000, 667000),
- CORE_DVFS("emc", 2, 1, KHZ, 102000, 408000, 408000, 408000, 408000, 667000, 667000, 800000, 900000),
+ CORE_DVFS("emc", 2, 1, KHZ, 102000, 450000, 450000, 450000, 450000, 667000, 667000, 800000, 900000),
CORE_DVFS("emc", 3, 1, KHZ, 1, 1, 1, 1, 1, 1, 625000, 625000, 625000),
CORE_DVFS("sbus", 0, 1, KHZ, 1, 136000, 164000, 191000, 216000, 216000, 216000, 216000, 216000),
- CORE_DVFS("sbus", 1, 1, KHZ, 51000, 205000, 205000, 227000, 227000, 267000, 267000, 267000, 267000),
- CORE_DVFS("sbus", 2, 1, KHZ, 51000, 205000, 205000, 227000, 227000, 267000, 334000, 334000, 334000),
- CORE_DVFS("sbus", 3, 1, KHZ, 1, 1, 1, 1, 1, 1, 378000, 378000, 378000),
+ CORE_DVFS("sbus", 1, 1, KHZ, 102000, 205000, 205000, 227000, 227000, 267000, 267000, 267000, 267000),
+ CORE_DVFS("sbus", 2, 1, KHZ, 102000, 205000, 205000, 227000, 227000, 267000, 334000, 334000, 334000),
+ CORE_DVFS("sbus", 3, 1, KHZ, 1, 1, 1, 1, 1, 1, 334000, 334000, 334000),
CORE_DVFS("vi", 0, 1, KHZ, 1, 216000, 285000, 300000, 300000, 300000, 300000, 300000, 300000),
CORE_DVFS("vi", 1, 1, KHZ, 1, 216000, 267000, 300000, 371000, 409000, 409000, 409000, 409000),
@@ -243,21 +249,21 @@ static struct dvfs core_dvfs_table[] = {
CORE_DVFS("3d2", 0, 1, KHZ, 1, 234000, 285000, 332000, 380000, 416000, 416000, 416000, 416000),
CORE_DVFS("se", 0, 1, KHZ, 1, 267000, 285000, 332000, 380000, 416000, 416000, 416000, 416000),
- CORE_DVFS("vde", 1, 1, KHZ, 1, 228000, 275000, 332000, 380000, 416000, 416000, 416000, 416000),
- CORE_DVFS("mpe", 1, 1, KHZ, 1, 234000, 285000, 332000, 380000, 416000, 416000, 416000, 416000),
- CORE_DVFS("2d", 1, 1, KHZ, 1, 267000, 285000, 332000, 380000, 416000, 416000, 416000, 416000),
- CORE_DVFS("epp", 1, 1, KHZ, 1, 267000, 285000, 332000, 380000, 416000, 416000, 416000, 416000),
- CORE_DVFS("3d", 1, 1, KHZ, 1, 234000, 285000, 332000, 380000, 416000, 416000, 416000, 416000),
- CORE_DVFS("3d2", 1, 1, KHZ, 1, 234000, 285000, 332000, 380000, 416000, 416000, 416000, 416000),
- CORE_DVFS("se", 1, 1, KHZ, 1, 267000, 285000, 332000, 380000, 416000, 416000, 416000, 416000),
-
- CORE_DVFS("vde", 2, 1, KHZ, 1, 247000, 304000, 352000, 400000, 437000, 484000, 520000, 600000),
- CORE_DVFS("mpe", 2, 1, KHZ, 1, 247000, 304000, 361000, 408000, 446000, 484000, 520000, 600000),
- CORE_DVFS("2d", 2, 1, KHZ, 1, 267000, 304000, 361000, 408000, 446000, 484000, 520000, 600000),
- CORE_DVFS("epp", 2, 1, KHZ, 1, 267000, 304000, 361000, 408000, 446000, 484000, 520000, 600000),
- CORE_DVFS("3d", 2, 1, KHZ, 1, 247000, 304000, 361000, 408000, 446000, 484000, 520000, 600000),
- CORE_DVFS("3d2", 2, 1, KHZ, 1, 247000, 304000, 361000, 408000, 446000, 484000, 520000, 600000),
- CORE_DVFS("se", 2, 1, KHZ, 1, 267000, 304000, 361000, 408000, 446000, 484000, 520000, 600000),
+ CORE_DVFS("vde", 1, 1, KHZ, 200000, 228000, 275000, 332000, 380000, 416000, 416000, 416000, 416000),
+ CORE_DVFS("mpe", 1, 1, KHZ, 200000, 234000, 285000, 332000, 380000, 416000, 416000, 416000, 416000),
+ CORE_DVFS("2d", 1, 1, KHZ, 200000, 267000, 285000, 332000, 380000, 416000, 416000, 416000, 416000),
+ CORE_DVFS("epp", 1, 1, KHZ, 200000, 267000, 285000, 332000, 380000, 416000, 416000, 416000, 416000),
+ CORE_DVFS("3d", 1, 1, KHZ, 200000, 234000, 285000, 332000, 380000, 416000, 416000, 416000, 416000),
+ CORE_DVFS("3d2", 1, 1, KHZ, 200000, 234000, 285000, 332000, 380000, 416000, 416000, 416000, 416000),
+ CORE_DVFS("se", 1, 1, KHZ, 200000, 267000, 285000, 332000, 380000, 416000, 416000, 416000, 416000),
+
+ CORE_DVFS("vde", 2, 1, KHZ, 200000, 247000, 304000, 352000, 400000, 437000, 484000, 520000, 600000),
+ CORE_DVFS("mpe", 2, 1, KHZ, 200000, 247000, 304000, 361000, 408000, 446000, 484000, 520000, 600000),
+ CORE_DVFS("2d", 2, 1, KHZ, 200000, 267000, 304000, 361000, 408000, 446000, 484000, 520000, 600000),
+ CORE_DVFS("epp", 2, 1, KHZ, 200000, 267000, 304000, 361000, 408000, 446000, 484000, 520000, 600000),
+ CORE_DVFS("3d", 2, 1, KHZ, 200000, 247000, 304000, 361000, 408000, 446000, 484000, 520000, 600000),
+ CORE_DVFS("3d2", 2, 1, KHZ, 200000, 247000, 304000, 361000, 408000, 446000, 484000, 520000, 600000),
+ CORE_DVFS("se", 2, 1, KHZ, 200000, 267000, 304000, 361000, 408000, 446000, 484000, 520000, 600000),
CORE_DVFS("vde", 3, 1, KHZ, 1, 1, 1, 1, 1, 1, 484000, 484000, 484000),
CORE_DVFS("mpe", 3, 1, KHZ, 1, 1, 1, 1, 1, 1, 484000, 484000, 484000),
@@ -268,14 +274,14 @@ static struct dvfs core_dvfs_table[] = {
CORE_DVFS("se", 3, 1, KHZ, 1, 1, 1, 1, 1, 1, 625000, 625000, 625000),
CORE_DVFS("host1x", 0, 1, KHZ, 1, 152000, 188000, 222000, 254000, 267000, 267000, 267000, 267000),
- CORE_DVFS("host1x", 1, 1, KHZ, 1, 152000, 188000, 222000, 254000, 267000, 267000, 267000, 267000),
- CORE_DVFS("host1x", 2, 1, KHZ, 1, 152000, 188000, 222000, 254000, 267000, 267000, 267000, 300000),
+ CORE_DVFS("host1x", 1, 1, KHZ, 100000, 152000, 188000, 222000, 254000, 267000, 267000, 267000, 267000),
+ CORE_DVFS("host1x", 2, 1, KHZ, 100000, 152000, 188000, 222000, 254000, 267000, 267000, 267000, 300000),
CORE_DVFS("host1x", 3, 1, KHZ, 1, 1, 1, 1, 1, 1, 242000, 242000, 242000),
CORE_DVFS("cbus", 0, 1, KHZ, 1, 228000, 275000, 332000, 380000, 416000, 416000, 416000, 416000),
- CORE_DVFS("cbus", 1, 1, KHZ, 1, 228000, 275000, 332000, 380000, 416000, 416000, 416000, 416000),
- CORE_DVFS("cbus", 2, 1, KHZ, 1, 247000, 304000, 352000, 400000, 437000, 484000, 520000, 600000),
- CORE_DVFS("cbus", 3, 1, KHZ, 1, 484000, 484000, 484000, 484000, 484000, 484000, 484000, 484000),
+ CORE_DVFS("cbus", 1, 1, KHZ, 200000, 228000, 275000, 332000, 380000, 416000, 416000, 416000, 416000),
+ CORE_DVFS("cbus", 2, 1, KHZ, 200000, 247000, 304000, 352000, 400000, 437000, 484000, 520000, 600000),
+ CORE_DVFS("cbus", 3, 1, KHZ, 1, 1, 1, 1, 1, 1, 484000, 484000, 484000),
CORE_DVFS("pll_c", -1, 1, KHZ, 533000, 667000, 667000, 800000, 800000, 1066000, 1066000, 1066000, 1200000),
@@ -287,7 +293,7 @@ static struct dvfs core_dvfs_table[] = {
*/
CORE_DVFS("pll_m", -1, 1, KHZ, 533000, 667000, 667000, 800000, 800000, 1066000, 1066000, 1066000, 1066000),
#ifdef CONFIG_TEGRA_PLLM_RESTRICTED
- CORE_DVFS("pll_m", 2, 1, KHZ, 533000, 800000, 800000, 800000, 800000, 1066000, 1066000, 1066000, 1066000),
+ CORE_DVFS("pll_m", 2, 1, KHZ, 533000, 900000, 900000, 900000, 900000, 1066000, 1066000, 1066000, 1066000),
#endif
/* Core voltages (mV): 950, 1000, 1050, 1100, 1150, 1200, 1250, 1300, 1350 */
/* Clock limits for I/O peripherals */
@@ -299,36 +305,27 @@ static struct dvfs core_dvfs_table[] = {
CORE_DVFS("fuse_burn", -1, 1, KHZ, 1, 1, 1, 1, 26000, 26000, 26000, 26000, 26000),
CORE_DVFS("sdmmc1", -1, 1, KHZ, 104000, 104000, 104000, 104000, 104000, 208000, 208000, 208000, 208000),
CORE_DVFS("sdmmc3", -1, 1, KHZ, 104000, 104000, 104000, 104000, 104000, 208000, 208000, 208000, 208000),
- CORE_DVFS("ndflash", -1, 1, KHZ, 1, 120000, 120000, 120000, 200000, 200000, 200000, 200000, 200000),
+ CORE_DVFS("ndflash", -1, 1, KHZ, 120000, 120000, 120000, 120000, 200000, 200000, 200000, 200000, 200000),
CORE_DVFS("nor", 0, 1, KHZ, 1, 115000, 130000, 130000, 133000, 133000, 133000, 133000, 133000),
- CORE_DVFS("nor", 1, 1, KHZ, 1, 115000, 130000, 130000, 133000, 133000, 133000, 133000, 133000),
- CORE_DVFS("nor", 2, 1, KHZ, 1, 115000, 130000, 130000, 133000, 133000, 133000, 133000, 133000),
+ CORE_DVFS("nor", 1, 1, KHZ, 102000, 115000, 130000, 130000, 133000, 133000, 133000, 133000, 133000),
+ CORE_DVFS("nor", 2, 1, KHZ, 102000, 115000, 130000, 130000, 133000, 133000, 133000, 133000, 133000),
CORE_DVFS("nor", 3, 1, KHZ, 1, 1, 1, 1, 1, 1, 108000, 108000, 108000),
- CORE_DVFS("sbc1", -1, 1, KHZ, 1, 52000, 60000, 60000, 60000, 100000, 100000, 100000, 100000),
- CORE_DVFS("sbc2", -1, 1, KHZ, 1, 52000, 60000, 60000, 60000, 100000, 100000, 100000, 100000),
- CORE_DVFS("sbc3", -1, 1, KHZ, 1, 52000, 60000, 60000, 60000, 100000, 100000, 100000, 100000),
- CORE_DVFS("sbc4", -1, 1, KHZ, 1, 52000, 60000, 60000, 60000, 100000, 100000, 100000, 100000),
- CORE_DVFS("sbc5", -1, 1, KHZ, 1, 52000, 60000, 60000, 60000, 100000, 100000, 100000, 100000),
- CORE_DVFS("sbc6", -1, 1, KHZ, 1, 52000, 60000, 60000, 60000, 100000, 100000, 100000, 100000),
-
- CORE_DVFS("usbd", -1, 1, KHZ, 1, 480000, 480000, 480000, 480000, 480000, 480000, 480000, 480000),
- CORE_DVFS("usb2", -1, 1, KHZ, 1, 480000, 480000, 480000, 480000, 480000, 480000, 480000, 480000),
- CORE_DVFS("usb3", -1, 1, KHZ, 1, 480000, 480000, 480000, 480000, 480000, 480000, 480000, 480000),
+ CORE_DVFS("sbc1", -1, 1, KHZ, 36000, 52000, 60000, 60000, 60000, 100000, 100000, 100000, 100000),
+ CORE_DVFS("sbc2", -1, 1, KHZ, 36000, 52000, 60000, 60000, 60000, 100000, 100000, 100000, 100000),
+ CORE_DVFS("sbc3", -1, 1, KHZ, 36000, 52000, 60000, 60000, 60000, 100000, 100000, 100000, 100000),
+ CORE_DVFS("sbc4", -1, 1, KHZ, 36000, 52000, 60000, 60000, 60000, 100000, 100000, 100000, 100000),
+ CORE_DVFS("sbc5", -1, 1, KHZ, 36000, 52000, 60000, 60000, 60000, 100000, 100000, 100000, 100000),
+ CORE_DVFS("sbc6", -1, 1, KHZ, 36000, 52000, 60000, 60000, 60000, 100000, 100000, 100000, 100000),
CORE_DVFS("sata", -1, 1, KHZ, 1, 216000, 216000, 216000, 216000, 216000, 216000, 216000, 216000),
CORE_DVFS("sata_oob", -1, 1, KHZ, 1, 216000, 216000, 216000, 216000, 216000, 216000, 216000, 216000),
- CORE_DVFS("pcie", -1, 1, KHZ, 1, 250000, 250000, 250000, 250000, 250000, 250000, 250000, 250000),
- CORE_DVFS("afi", -1, 1, KHZ, 1, 250000, 250000, 250000, 250000, 250000, 250000, 250000, 250000),
- CORE_DVFS("pll_e", -1, 1, KHZ, 1, 100000, 100000, 100000, 100000, 100000, 100000, 100000, 100000),
- CORE_DVFS("tvdac", -1, 1, KHZ, 1, 220000, 220000, 220000, 220000, 220000, 220000, 220000, 220000),
CORE_DVFS("tvo", -1, 1, KHZ, 1, 1, 297000, 297000, 297000, 297000, 297000, 297000, 297000),
CORE_DVFS("cve", -1, 1, KHZ, 1, 1, 297000, 297000, 297000, 297000, 297000, 297000, 297000),
- CORE_DVFS("dsia", -1, 1, KHZ, 1, 275000, 275000, 275000, 275000, 275000, 275000, 275000, 275000),
- CORE_DVFS("dsib", -1, 1, KHZ, 1, 275000, 275000, 275000, 275000, 275000, 275000, 275000, 275000),
- CORE_DVFS("hdmi", -1, 1, KHZ, 1, 148500, 148500, 148500, 148500, 148500, 148500, 148500, 148500),
+ CORE_DVFS("dsia", -1, 1, KHZ, 432500, 432500, 432500, 432500, 432500, 432500, 432500, 432500, 432500),
+ CORE_DVFS("dsib", -1, 1, KHZ, 432500, 432500, 432500, 432500, 432500, 432500, 432500, 432500, 432500),
/*
* The clock rate for the display controllers that determines the
@@ -337,19 +334,23 @@ static struct dvfs core_dvfs_table[] = {
* and let the display driver call tegra_dvfs_set_rate manually
*/
CORE_DVFS("disp1", 0, 0, KHZ, 1, 120000, 120000, 120000, 120000, 190000, 190000, 190000, 190000),
- CORE_DVFS("disp1", 1, 0, KHZ, 1, 155000, 268000, 268000, 268000, 268000, 268000, 268000, 268000),
- CORE_DVFS("disp1", 2, 0, KHZ, 1, 155000, 268000, 268000, 268000, 268000, 268000, 268000, 268000),
+ CORE_DVFS("disp1", 1, 0, KHZ, 155000, 155000, 268000, 268000, 268000, 268000, 268000, 268000, 268000),
+ CORE_DVFS("disp1", 2, 0, KHZ, 155000, 155000, 268000, 268000, 268000, 268000, 268000, 268000, 268000),
CORE_DVFS("disp1", 3, 0, KHZ, 1, 120000, 120000, 120000, 120000, 190000, 190000, 190000, 190000),
CORE_DVFS("disp2", 0, 0, KHZ, 1, 120000, 120000, 120000, 120000, 190000, 190000, 190000, 190000),
- CORE_DVFS("disp2", 1, 0, KHZ, 1, 155000, 268000, 268000, 268000, 268000, 268000, 268000, 268000),
- CORE_DVFS("disp2", 2, 0, KHZ, 1, 155000, 268000, 268000, 268000, 268000, 268000, 268000, 268000),
+ CORE_DVFS("disp2", 1, 0, KHZ, 155000, 155000, 268000, 268000, 268000, 268000, 268000, 268000, 268000),
+ CORE_DVFS("disp2", 2, 0, KHZ, 155000, 155000, 268000, 268000, 268000, 268000, 268000, 268000, 268000),
CORE_DVFS("disp2", 3, 0, KHZ, 1, 120000, 120000, 120000, 120000, 190000, 190000, 190000, 190000),
- CORE_DVFS("pwm", -1, 1, KHZ, 1, 408000, 408000, 408000, 408000, 408000, 408000, 408000, 408000),
- CORE_DVFS("spdif_out", -1, 1, KHZ, 1, 26000, 26000, 26000, 26000, 26000, 26000, 26000, 26000),
+ CORE_DVFS("pwm", -1, 1, KHZ, 204000, 408000, 408000, 408000, 408000, 408000, 408000, 408000, 408000),
};
+/* CPU alternative DVFS table for cold zone */
+static unsigned long cpu_cold_freqs[MAX_DVFS_FREQS];
+
+/* CPU alternative DVFS table for single G CPU core 0 */
+static unsigned long *cpu_0_freqs;
int tegra_dvfs_disable_core_set(const char *arg, const struct kernel_param *kp)
{
@@ -471,19 +472,18 @@ static void __init init_dvfs_cold(struct dvfs *d, int nominal_mv_index)
for (i = 0; i < d->num_freqs; i++) {
offs = cpu_cold_offs_mhz[i] * MHZ;
if (i > nominal_mv_index)
- d->alt_freqs[i] = d->alt_freqs[i - 1];
+ cpu_cold_freqs[i] = cpu_cold_freqs[i - 1];
else if (d->freqs[i] > offs)
- d->alt_freqs[i] = d->freqs[i] - offs;
+ cpu_cold_freqs[i] = d->freqs[i] - offs;
else {
- d->alt_freqs[i] = d->freqs[i];
+ cpu_cold_freqs[i] = d->freqs[i];
pr_warn("tegra3_dvfs: cold offset %lu is too high for"
" regular dvfs limit %lu\n", offs, d->freqs[i]);
}
if (i)
- BUG_ON(d->alt_freqs[i] < d->alt_freqs[i - 1]);
+ BUG_ON(cpu_cold_freqs[i] < cpu_cold_freqs[i - 1]);
}
- d->alt_freqs_state = ALT_FREQS_DISABLED;
}
static bool __init match_dvfs_one(struct dvfs *d, int speedo_id, int process_id)
@@ -498,6 +498,35 @@ static bool __init match_dvfs_one(struct dvfs *d, int speedo_id, int process_id)
return true;
}
+static void __init init_cpu_0_dvfs(struct dvfs *cpud)
+{
+ int i;
+ struct dvfs *d = NULL;
+
+ /* Init single G CPU core 0 dvfs if this particular SKU/bin has it.
+ Max rates in multi-core and single-core tables must be the same */
+ for (i = 0; i < ARRAY_SIZE(cpu_0_dvfs_table); i++) {
+ if (match_dvfs_one(&cpu_0_dvfs_table[i],
+ cpud->speedo_id, cpud->process_id)) {
+ d = &cpu_0_dvfs_table[i];
+ break;
+ }
+ }
+
+ if (d) {
+ for (i = 0; i < cpud->num_freqs; i++) {
+ d->freqs[i] *= d->freqs_mult;
+ if (d->freqs[i] == 0) {
+ BUG_ON(i == 0);
+ d->freqs[i] = d->freqs[i - 1];
+ }
+ }
+ BUG_ON(cpud->freqs[cpud->num_freqs - 1] !=
+ d->freqs[cpud->num_freqs - 1]);
+ cpu_0_freqs = d->freqs;
+ }
+}
+
static int __init get_cpu_nominal_mv_index(
int speedo_id, int process_id, struct dvfs **cpu_dvfs)
{
@@ -644,7 +673,10 @@ void __init tegra_soc_init_dvfs(void)
/* Initialize matching cpu dvfs entry already found when nominal
voltage was determined */
init_dvfs_one(cpu_dvfs, cpu_nominal_mv_index);
+
+ /* Initialize alternative cold zone and single core tables */
init_dvfs_cold(cpu_dvfs, cpu_nominal_mv_index);
+ init_cpu_0_dvfs(cpu_dvfs);
/* Finally disable dvfs on rails if necessary */
if (tegra_dvfs_core_disabled)
@@ -660,14 +692,18 @@ void __init tegra_soc_init_dvfs(void)
tegra_dvfs_core_disabled ? "disabled" : "enabled");
}
-void tegra_cpu_dvfs_alter(int edp_thermal_index, bool before_clk_update)
+void tegra_cpu_dvfs_alter(int edp_thermal_index, const cpumask_t *cpus,
+ bool before_clk_update)
{
- bool enable = !edp_thermal_index;
-
- if (enable != before_clk_update) {
- int ret = tegra_dvfs_alt_freqs_set(cpu_dvfs, enable);
- WARN_ONCE(ret, "tegra dvfs: failed to set CPU alternative"
- " frequency limits for cold temeperature\n");
+ bool cpu_warm = !!edp_thermal_index;
+ unsigned int n = cpumask_weight(cpus);
+ unsigned long *alt_freqs = cpu_warm ?
+ (n > 1 ? NULL : cpu_0_freqs) : cpu_cold_freqs;
+
+ if (cpu_warm == before_clk_update) {
+ int ret = tegra_dvfs_alt_freqs_set(cpu_dvfs, alt_freqs);
+ WARN_ONCE(ret, "tegra dvfs: failed to update CPU alternative"
+ " frequency limits\n");
}
}
@@ -781,8 +817,6 @@ static void core_cap_update(void)
static void core_cap_enable(bool enable)
{
- int i;
-
if (enable)
tegra3_core_cap.refcnt++;
else if (tegra3_core_cap.refcnt)
@@ -883,7 +917,7 @@ void tegra_dvfs_core_cap_level_set(int level)
static int __init init_core_cap_one(struct clk *c, unsigned long *freqs)
{
- int i, v, next_v;
+ int i, v, next_v = 0;
unsigned long rate, next_rate = 0;
for (i = 0; i < ARRAY_SIZE(core_millivolts); i++) {
@@ -904,7 +938,7 @@ static int __init init_core_cap_one(struct clk *c, unsigned long *freqs)
next_v = tegra_dvfs_predict_millivolts(
c->parent, next_rate);
- if (IS_ERR_VALUE(next_rate)) {
+ if (IS_ERR_VALUE(next_v)) {
pr_debug("tegra3_dvfs: failed to predict %s mV"
" for rate %lu", c->name, next_rate);
return -EINVAL;
diff --git a/arch/arm/mach-tegra/tegra3_emc.c b/arch/arm/mach-tegra/tegra3_emc.c
index 0725980bfa40..a138091d9197 100644
--- a/arch/arm/mach-tegra/tegra3_emc.c
+++ b/arch/arm/mach-tegra/tegra3_emc.c
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/tegra3_emc.c
*
- * Copyright (C) 2011 NVIDIA Corporation
+ * 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
@@ -45,6 +45,8 @@ static bool emc_enable;
#endif
module_param(emc_enable, bool, 0644);
+u8 tegra_emc_bw_efficiency = 35;
+
#define EMC_MIN_RATE_DDR3 25500000
#define EMC_STATUS_UPDATE_TIMEOUT 100
#define TEGRA_EMC_TABLE_MAX_SIZE 16
@@ -187,7 +189,13 @@ enum {
static int emc_num_burst_regs;
-static struct clk_mux_sel tegra_emc_clk_sel[TEGRA_EMC_TABLE_MAX_SIZE];
+struct emc_sel {
+ struct clk *input;
+ u32 value;
+ unsigned long input_rate;
+};
+
+static struct emc_sel tegra_emc_clk_sel[TEGRA_EMC_TABLE_MAX_SIZE];
static struct tegra_emc_table start_timing;
static const struct tegra_emc_table *emc_timing;
static unsigned long dram_over_temp_state = DRAM_OVER_TEMP_NONE;
@@ -350,6 +358,12 @@ static inline void disable_early_ack(u32 mc_override)
override_val |= mc_override & MC_EMEM_ARB_OVERRIDE_EACK_MASK;
}
+static inline void enable_early_ack(u32 mc_override)
+{
+ mc_writel((mc_override | MC_EMEM_ARB_OVERRIDE_EACK_MASK),
+ MC_EMEM_ARB_OVERRIDE);
+}
+
static inline bool dqs_preset(const struct tegra_emc_table *next_timing,
const struct tegra_emc_table *last_timing)
{
@@ -489,6 +503,7 @@ static inline void do_clock_change(u32 clk_setting)
mc_readl(MC_EMEM_ADR_CFG); /* completes prev writes */
writel(clk_setting, (u32)clk_base + emc->reg);
+ readl((u32)clk_base + emc->reg);/* completes prev write */
err = wait_for_update(EMC_INTSTATUS,
EMC_INTSTATUS_CLKCHANGE_COMPLETE, true);
@@ -702,7 +717,7 @@ static inline void emc_cfg_power_restore(void)
* This function updates the shadow registers for a new clock frequency,
* and relies on the clock lock on the emc clock to avoid races between
* multiple frequency changes */
-int tegra_emc_set_rate(unsigned long rate)
+static int emc_set_rate(unsigned long rate, bool use_backup)
{
int i;
u32 clk_setting;
@@ -735,7 +750,8 @@ int tegra_emc_set_rate(unsigned long rate)
else
last_timing = emc_timing;
- clk_setting = tegra_emc_clk_sel[i].value;
+ clk_setting = use_backup ? emc->shared_bus_backup.value :
+ tegra_emc_clk_sel[i].value;
spin_lock_irqsave(&emc_access_lock, flags);
emc_set_clock(&tegra_emc_table[i], last_timing, clk_setting);
@@ -751,6 +767,17 @@ int tegra_emc_set_rate(unsigned long rate)
return 0;
}
+int tegra_emc_set_rate(unsigned long rate)
+{
+ return emc_set_rate(rate, false);
+}
+
+int tegra_emc_backup(unsigned long rate)
+{
+ BUG_ON(rate != emc->shared_bus_backup.bus_rate);
+ return emc_set_rate(rate, true);
+}
+
/* Select the closest EMC rate that is higher than the requested rate */
long tegra_emc_round_rate(unsigned long rate)
{
@@ -793,7 +820,7 @@ struct clk *tegra_emc_predict_parent(unsigned long rate, u32 *div_value)
int i;
if (!tegra_emc_table)
- return NULL;
+ return ERR_PTR(-ENOENT);
pr_debug("%s: %lu\n", __func__, rate);
@@ -802,33 +829,94 @@ struct clk *tegra_emc_predict_parent(unsigned long rate, u32 *div_value)
for (i = 0; i < tegra_emc_table_size; i++) {
if (tegra_emc_table[i].rate == rate) {
+ struct clk *p = tegra_emc_clk_sel[i].input;
+
*div_value = (tegra_emc_clk_sel[i].value &
EMC_CLK_DIV_MASK) >> EMC_CLK_DIV_SHIFT;
- return tegra_emc_clk_sel[i].input;
+ if (tegra_emc_clk_sel[i].input_rate != clk_get_rate(p))
+ return NULL;
+
+ return p;
}
}
-
- return NULL;
+ return ERR_PTR(-ENOENT);
}
-static const struct clk_mux_sel *find_matching_input(
- unsigned long table_rate,
- u32 *div_value)
+int find_matching_input(unsigned long table_rate, bool mc_same_freq,
+ struct emc_sel *emc_clk_sel, struct clk *cbus)
{
- unsigned long inp_rate;
+ u32 div_value = 0;
+ unsigned long input_rate = 0;
const struct clk_mux_sel *sel;
+ const struct clk_mux_sel *parent_sel = NULL;
+ const struct clk_mux_sel *backup_sel = NULL;
+
+ /* Table entries specify rate in kHz */
+ table_rate *= 1000;
for (sel = emc->inputs; sel->input != NULL; sel++) {
- /* Table entries specify rate in kHz */
- inp_rate = clk_get_rate(sel->input) / 1000;
+ if (sel->input == emc->shared_bus_backup.input) {
+ backup_sel = sel;
+ continue; /* skip backup souce */
+ }
- if ((inp_rate >= table_rate) &&
- (inp_rate % table_rate == 0)) {
- *div_value = 2 * inp_rate / table_rate - 2;
- return sel;
+ if (sel->input == emc->parent)
+ parent_sel = sel;
+
+ input_rate = clk_get_rate(sel->input);
+
+ if ((input_rate >= table_rate) &&
+ (input_rate % table_rate == 0)) {
+ div_value = 2 * input_rate / table_rate - 2;
+ break;
+ }
+ }
+
+#ifdef CONFIG_TEGRA_PLLM_RESTRICTED
+ /*
+ * When match not found, check if this rate can be backed-up by cbus
+ * Then, we will be able to re-lock boot parent PLLM, and use it as
+ * an undivided source. Backup is supported only on LPDDR2 platforms
+ * with restricted PLLM usage. Just one backup entry is recognized,
+ * and it must be between EMC maximum and half maximum rates.
+ */
+ if ((dram_type == DRAM_TYPE_LPDDR2) && (sel->input == NULL) &&
+ (emc->shared_bus_backup.bus_rate == 0) && cbus) {
+ BUG_ON(!parent_sel || !backup_sel);
+
+ if ((table_rate == clk_round_rate(cbus, table_rate)) &&
+ (table_rate < clk_get_max_rate(emc)) &&
+ (table_rate >= clk_get_max_rate(emc) / 2)) {
+ emc->shared_bus_backup.bus_rate = table_rate;
+
+ /* Get ready emc clock backup selection settings */
+ emc->shared_bus_backup.value =
+ (backup_sel->value << EMC_CLK_SOURCE_SHIFT) |
+ (cbus->div << EMC_CLK_DIV_SHIFT) |
+ (mc_same_freq ? EMC_CLK_MC_SAME_FREQ : 0);
+
+ /* Select undivided PLLM as regular source */
+ sel = parent_sel;
+ input_rate = table_rate;
+ div_value = 0;
}
}
- return NULL;
+#endif
+
+ if (sel->input) {
+ emc_clk_sel->input = sel->input;
+ emc_clk_sel->input_rate = input_rate;
+
+ /* Get ready emc clock selection settings for this table rate */
+ emc_clk_sel->value = sel->value << EMC_CLK_SOURCE_SHIFT;
+ emc_clk_sel->value |= (div_value << EMC_CLK_DIV_SHIFT);
+ if ((div_value == 0) && (emc_clk_sel->input == emc->parent))
+ emc_clk_sel->value |= EMC_CLK_LOW_JITTER_ENABLE;
+ if (mc_same_freq)
+ emc_clk_sel->value |= EMC_CLK_MC_SAME_FREQ;
+ return 0;
+ }
+ return -EINVAL;
}
static void adjust_emc_dvfs_table(const struct tegra_emc_table *table,
@@ -932,10 +1020,10 @@ static struct notifier_block tegra_emc_resume_nb = {
void tegra_init_emc(const struct tegra_emc_table *table, int table_size)
{
int i, mv;
- u32 reg, div_value;
+ u32 reg;
bool max_entry = false;
unsigned long boot_rate, max_rate;
- const struct clk_mux_sel *sel;
+ struct clk *cbus = tegra_get_clock_by_name("cbus");
emc_stats.clkchange_count = 0;
spin_lock_init(&emc_stats.spinlock);
@@ -979,14 +1067,16 @@ void tegra_init_emc(const struct tegra_emc_table *table, int table_size)
/* Match EMC source/divider settings with table entries */
for (i = 0; i < tegra_emc_table_size; i++) {
+ bool mc_same_freq = MC_EMEM_ARB_MISC0_EMC_SAME_FREQ &
+ table[i].burst_regs[MC_EMEM_ARB_MISC0_INDEX];
unsigned long table_rate = table[i].rate;
if (!table_rate)
continue;
BUG_ON(table[i].rev != table[0].rev);
- sel = find_matching_input(table_rate, &div_value);
- if (!sel)
+ if (find_matching_input(table_rate, mc_same_freq,
+ &tegra_emc_clk_sel[i], cbus))
continue;
if (table_rate == boot_rate)
@@ -994,21 +1084,6 @@ void tegra_init_emc(const struct tegra_emc_table *table, int table_size)
if (table_rate == max_rate)
max_entry = true;
-
- tegra_emc_clk_sel[i] = *sel;
- BUG_ON(div_value >
- (EMC_CLK_DIV_MASK >> EMC_CLK_DIV_SHIFT));
- tegra_emc_clk_sel[i].value <<= EMC_CLK_SOURCE_SHIFT;
- tegra_emc_clk_sel[i].value |= (div_value << EMC_CLK_DIV_SHIFT);
-
- if ((div_value == 0) &&
- (tegra_emc_clk_sel[i].input == emc->parent)) {
- tegra_emc_clk_sel[i].value |= EMC_CLK_LOW_JITTER_ENABLE;
- }
-
- if (table[i].burst_regs[MC_EMEM_ARB_MISC0_INDEX] &
- MC_EMEM_ARB_MISC0_EMC_SAME_FREQ)
- tegra_emc_clk_sel[i].value |= EMC_CLK_MC_SAME_FREQ;
}
/* Validate EMC rate and voltage limits */
@@ -1163,6 +1238,51 @@ int tegra_emc_set_over_temp_state(unsigned long state)
return 0;
}
+/* non-zero state value will reduce eack_disable_refcnt */
+static int tegra_emc_set_eack_state(unsigned long state)
+{
+ unsigned long flags;
+ u32 mc_override;
+ static int eack_disable_refcnt = 0;
+
+ spin_lock_irqsave(&emc_access_lock, flags);
+
+ /*
+ * refcnt > 0 implies there is at least one client requiring eack
+ * disabled. refcnt of 0 implies eack is enabled
+ */
+ if (eack_disable_refcnt == 1 && state) {
+ mc_override = mc_readl(MC_EMEM_ARB_OVERRIDE);
+ enable_early_ack(mc_override);
+ } else if (eack_disable_refcnt == 0 && !state) {
+ mc_override = mc_readl(MC_EMEM_ARB_OVERRIDE);
+ disable_early_ack(mc_override);
+ }
+
+ if (state) {
+ if (likely(eack_disable_refcnt > 0)) {
+ --eack_disable_refcnt;
+ } else {
+ pr_err("%s: Ignored a request to underflow eack "
+ "disable reference counter\n",__func__);
+ dump_stack();
+ }
+ } else {
+ ++eack_disable_refcnt;
+ }
+
+ spin_unlock_irqrestore(&emc_access_lock, flags);
+ return 0;
+}
+
+int tegra_emc_enable_eack(void) {
+ return tegra_emc_set_eack_state(1);
+}
+
+int tegra_emc_disable_eack(void) {
+ return tegra_emc_set_eack_state(0);
+}
+
#ifdef CONFIG_DEBUG_FS
static struct dentry *emc_debugfs_root;
@@ -1222,6 +1342,43 @@ static int over_temp_state_set(void *data, u64 val)
DEFINE_SIMPLE_ATTRIBUTE(over_temp_state_fops, over_temp_state_get,
over_temp_state_set, "%llu\n");
+static int eack_state_get(void *data, u64 *val)
+{
+ unsigned long flags;
+ u32 mc_override;
+
+ spin_lock_irqsave(&emc_access_lock, flags);
+ mc_override = mc_readl(MC_EMEM_ARB_OVERRIDE);
+ spin_unlock_irqrestore(&emc_access_lock, flags);
+
+ *val = (mc_override & MC_EMEM_ARB_OVERRIDE_EACK_MASK);
+ return 0;
+}
+
+static int eack_state_set(void *data, u64 val)
+{
+ tegra_emc_set_eack_state(val);
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(eack_state_fops, eack_state_get,
+ eack_state_set, "%llu\n");
+
+static int efficiency_get(void *data, u64 *val)
+{
+ *val = tegra_emc_bw_efficiency;
+ return 0;
+}
+static int efficiency_set(void *data, u64 val)
+{
+ tegra_emc_bw_efficiency = (val > 100) ? 100 : val;
+ if (emc)
+ tegra_clk_shared_bus_update(emc);
+
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(efficiency_fops, efficiency_get,
+ efficiency_set, "%llu\n");
+
static int __init tegra_emc_debug_init(void)
{
if (!tegra_emc_table)
@@ -1243,6 +1400,14 @@ static int __init tegra_emc_debug_init(void)
emc_debugfs_root, NULL, &over_temp_state_fops))
goto err_out;
+ if (!debugfs_create_file(
+ "eack_state", S_IRUGO | S_IWUSR, emc_debugfs_root, NULL, &eack_state_fops))
+ goto err_out;
+
+ if (!debugfs_create_file("efficiency", S_IRUGO | S_IWUSR,
+ emc_debugfs_root, NULL, &efficiency_fops))
+ goto err_out;
+
return 0;
err_out:
diff --git a/arch/arm/mach-tegra/tegra3_emc.h b/arch/arm/mach-tegra/tegra3_emc.h
index cfde92c1355a..f59654295ba4 100644
--- a/arch/arm/mach-tegra/tegra3_emc.h
+++ b/arch/arm/mach-tegra/tegra3_emc.h
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/tegra3_emc.h
*
- * Copyright (C) 2011 NVIDIA Corporation
+ * 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
@@ -27,6 +27,8 @@
#define TEGRA_EMC_BRIDGE_RATE_MIN 300000000
#define TEGRA_EMC_BRIDGE_MVOLTS_MIN 1200
+extern u8 tegra_emc_bw_efficiency;
+
struct tegra_emc_table {
u8 rev;
unsigned long rate;
diff --git a/arch/arm/mach-tegra/tegra3_host1x_devices.h b/arch/arm/mach-tegra/tegra3_host1x_devices.h
new file mode 100644
index 000000000000..38a5eabf037f
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra3_host1x_devices.h
@@ -0,0 +1,26 @@
+/*
+ * drivers/video/tegra/host/tegra3_host1x_devices.h
+ *
+ * Tegra3 Graphics Host Devices
+ *
+ * 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 TEGRA3_HOST1X_DEVICES_H
+#define TEGRA3_HOST1X_DEVICES_H
+
+int tegra3_register_host1x_devices(void);
+
+#endif
diff --git a/arch/arm/mach-tegra/tegra3_speedo.c b/arch/arm/mach-tegra/tegra3_speedo.c
index bd880bc7ca8b..78afb2804088 100644
--- a/arch/arm/mach-tegra/tegra3_speedo.c
+++ b/arch/arm/mach-tegra/tegra3_speedo.c
@@ -108,8 +108,8 @@ static const u32 cpu_process_speedos[][CPU_PROCESS_CORNERS_NUM] = {
/* T30 Automotives */
/* threshold_index 12: cpu_speedo_id 9 & 10
- * 0,1,2 values correspond to speedo_id 9
- * 3,4,5 values correspond to speedo_id 10 */
+ * 0,1,2 values correspond to speedo_id 9/14
+ * 3,4,5 values correspond to speedo_id 10/15*/
{300, 311, 360, 371, 381, 415, 431},
{300, 311, 410, 431, UINT_MAX}, /* [13]: cpu_speedo_id 11: T30 auto */
@@ -462,10 +462,31 @@ void tegra_init_speedo_data(void)
soc_speedo_id = 1;
}
if (threshold_index == 12 && cpu_process_id != INVALID_PROCESS_ID) {
- if (cpu_process_id <= 2)
- cpu_speedo_id = 9;
- else if (cpu_process_id >= 3 && cpu_process_id < 6)
- cpu_speedo_id = 10;
+ if (cpu_process_id <= 2) {
+ switch(fuse_sku) {
+ case 0xb0:
+ case 0xb1:
+ cpu_speedo_id = 9;
+ break;
+ case 0x90:
+ case 0x91:
+ cpu_speedo_id = 14;
+ default:
+ break;
+ }
+ } else if (cpu_process_id >= 3 && cpu_process_id < 6) {
+ switch(fuse_sku) {
+ case 0xb0:
+ case 0xb1:
+ cpu_speedo_id = 10;
+ break;
+ case 0x90:
+ case 0x91:
+ cpu_speedo_id = 15;
+ default:
+ break;
+ }
+ }
}
pr_info("Tegra3: CPU Speedo ID %d, Soc Speedo ID %d",
cpu_speedo_id, soc_speedo_id);
@@ -510,8 +531,8 @@ int tegra_package_id(void)
* latter is resolved by the dvfs code)
*/
static const int cpu_speedo_nominal_millivolts[] =
-/* speedo_id 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 */
- { 1125, 1150, 1150, 1150, 1237, 1237, 1237, 1150, 1150, 912, 850, 850, 1237, 1237};
+/* speedo_id 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 */
+ { 1125, 1150, 1150, 1150, 1237, 1237, 1237, 1150, 1150, 1007, 916, 850, 1237, 1237, 950, 900};
int tegra_cpu_speedo_mv(void)
{
diff --git a/arch/arm/mach-tegra/tegra3_thermal.c b/arch/arm/mach-tegra/tegra3_thermal.c
index 27f7a425e02a..f36f84ccddf4 100644
--- a/arch/arm/mach-tegra/tegra3_thermal.c
+++ b/arch/arm/mach-tegra/tegra3_thermal.c
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/tegra3_thermal.c
*
- * Copyright (C) 2010-2011 NVIDIA Corporation.
+ * 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
@@ -28,56 +28,32 @@
#include <mach/thermal.h>
#include <mach/edp.h>
#include <linux/slab.h>
+#include <linux/suspend.h>
#include "clock.h"
#include "cpu-tegra.h"
#include "dvfs.h"
-#define MAX_ZONES (16)
+static struct tegra_thermal_data *therm;
+static LIST_HEAD(tegra_therm_list);
+static DEFINE_MUTEX(tegra_therm_mutex);
-struct tegra_thermal {
- struct tegra_thermal_device *device;
- long temp_throttle_tj;
- long temp_shutdown_tj;
-#ifdef CONFIG_TEGRA_THERMAL_SYSFS
- struct thermal_zone_device *thz;
- int tc1;
- int tc2;
- long passive_delay;
-#else
- long temp_throttle_low_tj;
-#endif
-#ifdef CONFIG_TEGRA_EDP_LIMITS
- int edp_thermal_zone_val;
- long edp_offset;
- long hysteresis_edp;
-#endif
- struct mutex mutex;
-};
+static struct balanced_throttle *throttle_list;
+static int throttle_list_size;
-static struct tegra_thermal thermal_state = {
- .device = NULL,
#ifdef CONFIG_TEGRA_EDP_LIMITS
- .edp_thermal_zone_val = -1,
+static long edp_thermal_zone_val;
#endif
-};
-#ifndef CONFIG_TEGRA_THERMAL_SYSFS
-static bool throttle_enb;
+#ifdef CONFIG_TEGRA_SKIN_THROTTLE
+static int skin_devs_bitmap;
+static struct therm_est_subdevice *skin_devs[THERMAL_DEVICE_MAX];
+static int skin_devs_count;
#endif
+static bool tegra_thermal_suspend;
-#ifdef CONFIG_TEGRA_EDP_LIMITS
-static inline long edp2tj(struct tegra_thermal *thermal,
- long edp_temp)
-{
- return edp_temp + thermal->edp_offset;
-}
-
-static inline long tj2edp(struct tegra_thermal *thermal,
- long temp_tj)
-{
- return temp_tj - thermal->edp_offset;
-}
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *thermal_debugfs_root;
#endif
static inline long dev2tj(struct tegra_thermal_device *dev,
@@ -92,25 +68,74 @@ static inline long tj2dev(struct tegra_thermal_device *dev,
return tj_temp - dev->offset;
}
-#ifdef CONFIG_TEGRA_THERMAL_SYSFS
+static int tegra_thermal_get_temp_unlocked(long *tj_temp, bool offsetted)
+{
+ struct tegra_thermal_device *dev = NULL;
+ int ret = 0;
+
+#if defined(CONFIG_TEGRA_EDP_LIMITS) || defined(CONFIG_TEGRA_THERMAL_THROTTLE)
+ list_for_each_entry(dev, &tegra_therm_list, node)
+ if (dev->id == therm->throttle_edp_device_id)
+ break;
+#endif
+
+ if (dev) {
+ dev->get_temp(dev->data, tj_temp);
+ if (offsetted)
+ *tj_temp = dev2tj(dev, *tj_temp);
+ } else {
+ ret = -1;
+ }
-static int tegra_thermal_zone_bind(struct thermal_zone_device *thermal,
+ return ret;
+}
+
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
+
+static int tegra_thermal_zone_bind(struct thermal_zone_device *thz,
struct thermal_cooling_device *cdevice) {
- /* Support only Thermal Throttling (1 trip) for now */
- return thermal_zone_bind_cooling_device(thermal, 0, cdevice);
+
+ struct balanced_throttle *bthrot = cdevice->devdata;
+ struct tegra_thermal_device *device = thz->devdata;
+
+ if ((bthrot->id == BALANCED_THROTTLE_ID_TJ) &&
+ (device->id == therm->throttle_edp_device_id))
+ return thermal_zone_bind_cooling_device(thz, 0, cdevice);
+
+#ifdef CONFIG_TEGRA_SKIN_THROTTLE
+ if ((bthrot->id == BALANCED_THROTTLE_ID_SKIN) &&
+ (device->id == therm->skin_device_id))
+ return thermal_zone_bind_cooling_device(thz, 0, cdevice);
+#endif
+
+ return 0;
}
-static int tegra_thermal_zone_unbind(struct thermal_zone_device *thermal,
+static int tegra_thermal_zone_unbind(struct thermal_zone_device *thz,
struct thermal_cooling_device *cdevice) {
- /* Support only Thermal Throttling (1 trip) for now */
- return thermal_zone_unbind_cooling_device(thermal, 0, cdevice);
+ struct balanced_throttle *bthrot = cdevice->devdata;
+ struct tegra_thermal_device *device = thz->devdata;
+
+ if ((bthrot->id == BALANCED_THROTTLE_ID_TJ) &&
+ (device->id == therm->throttle_edp_device_id))
+ return thermal_zone_unbind_cooling_device(thz, 0, cdevice);
+
+#ifdef CONFIG_TEGRA_SKIN_THROTTLE
+ if ((bthrot->id == BALANCED_THROTTLE_ID_SKIN) &&
+ (device->id == therm->skin_device_id))
+ return thermal_zone_unbind_cooling_device(thz, 0, cdevice);
+#endif
+
+ return 0;
}
static int tegra_thermal_zone_get_temp(struct thermal_zone_device *thz,
unsigned long *temp)
{
- struct tegra_thermal *thermal = thz->devdata;
- thermal->device->get_temp(thermal->device->data, temp);
+ struct tegra_thermal_device *device = thz->devdata;
+
+ if (!tegra_thermal_suspend)
+ device->get_temp(device->data, temp);
return 0;
}
@@ -119,8 +144,6 @@ static int tegra_thermal_zone_get_trip_type(
struct thermal_zone_device *thermal,
int trip,
enum thermal_trip_type *type) {
-
- /* Support only Thermal Throttling (1 trip) for now */
if (trip != 0)
return -EINVAL;
@@ -132,13 +155,19 @@ static int tegra_thermal_zone_get_trip_type(
static int tegra_thermal_zone_get_trip_temp(struct thermal_zone_device *thz,
int trip,
unsigned long *temp) {
- struct tegra_thermal *thermal = thz->devdata;
+ struct tegra_thermal_device *device = thz->devdata;
- /* Support only Thermal Throttling (1 trip) for now */
if (trip != 0)
return -EINVAL;
- *temp = tj2dev(thermal->device, thermal->temp_throttle_tj);
+ if (device->id == therm->throttle_edp_device_id)
+ *temp = therm->temp_throttle;
+#ifdef CONFIG_TEGRA_SKIN_THROTTLE
+ else if (device->id == therm->skin_device_id)
+ *temp = therm->temp_throttle_skin;
+#endif
+ else
+ return -EINVAL;
return 0;
}
@@ -152,26 +181,29 @@ static struct thermal_zone_device_ops tegra_thermal_zone_ops = {
};
#endif
-/* The thermal sysfs handles notifying the throttling
- * cooling device */
-#ifndef CONFIG_TEGRA_THERMAL_SYSFS
-static void tegra_therm_throttle(bool enable)
+static int tegra_thermal_pm_notify(struct notifier_block *nb,
+ unsigned long event, void *data)
{
- if (throttle_enb != enable) {
- mutex_lock(&thermal_state.mutex);
- tegra_throttling_enable(enable);
- throttle_enb = enable;
- mutex_unlock(&thermal_state.mutex);
+ switch (event) {
+ case PM_SUSPEND_PREPARE:
+ tegra_thermal_suspend = true;
+ break;
+ case PM_POST_SUSPEND:
+ tegra_thermal_suspend = false;
+ break;
}
-}
-#endif
-/* Make sure this function remains stateless */
-void tegra_thermal_alert(void *data)
+ return NOTIFY_OK;
+};
+
+static struct notifier_block tegra_thermal_nb = {
+ .notifier_call = tegra_thermal_pm_notify,
+};
+
+static void tegra_thermal_alert_unlocked(void *data)
{
- struct tegra_thermal *thermal = data;
- int err;
- long temp_dev, temp_tj;
+ struct tegra_thermal_device *device = data;
+ long temp_tj;
long lo_limit_throttle_tj, hi_limit_throttle_tj;
long lo_limit_edp_tj = 0, hi_limit_edp_tj = 0;
long temp_low_dev, temp_low_tj;
@@ -182,45 +214,29 @@ void tegra_thermal_alert(void *data)
int i;
#endif
- if (thermal != &thermal_state)
- BUG();
-
- mutex_lock(&thermal_state.mutex);
-
-#ifdef CONFIG_TEGRA_THERMAL_SYSFS
- if (thermal->thz) {
- if (!thermal->thz->passive)
- thermal_zone_device_update(thermal->thz);
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
+ if (device->thz) {
+ if ((!device->thz->passive) && (!tegra_thermal_suspend))
+ thermal_zone_device_update(device->thz);
}
#endif
- err = thermal->device->get_temp(thermal->device->data, &temp_dev);
- if (err) {
- pr_err("%s: get temp fail(%d)", __func__, err);
- goto done;
- }
-
/* Convert all temps to tj and then do all work/logic in terms of
tj in order to avoid confusion */
- temp_tj = dev2tj(thermal->device, temp_dev);
- thermal->device->get_temp_low(thermal->device, &temp_low_dev);
- temp_low_tj = dev2tj(thermal->device, temp_low_dev);
+ if (tegra_thermal_get_temp_unlocked(&temp_tj, true))
+ return;
+ device->get_temp_low(device, &temp_low_dev);
+ temp_low_tj = dev2tj(device, temp_low_dev);
lo_limit_throttle_tj = temp_low_tj;
- hi_limit_throttle_tj = thermal->temp_throttle_tj;
-
-#ifndef CONFIG_TEGRA_THERMAL_SYSFS
- /* Check to see if we are currently throttling */
- if ((tegra_is_throttling() &&
- (temp_tj > thermal->temp_throttle_low_tj))
- || (temp_tj >= thermal->temp_throttle_tj)) {
- lo_limit_throttle_tj = thermal->temp_throttle_low_tj;
- hi_limit_throttle_tj = thermal->temp_shutdown_tj;
- }
-#else
- if (temp_tj > thermal->temp_throttle_tj) {
- lo_limit_throttle_tj = thermal->temp_throttle_tj;
- hi_limit_throttle_tj = thermal->temp_shutdown_tj;
+ hi_limit_throttle_tj = dev2tj(device, therm->temp_shutdown);
+
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
+ hi_limit_throttle_tj = dev2tj(device, therm->temp_throttle);
+
+ if (temp_tj > dev2tj(device, therm->temp_throttle)) {
+ lo_limit_throttle_tj = dev2tj(device, therm->temp_throttle);
+ hi_limit_throttle_tj = dev2tj(device, therm->temp_shutdown);
}
#endif
@@ -228,21 +244,21 @@ void tegra_thermal_alert(void *data)
tegra_get_cpu_edp_limits(&z, &zones_sz);
/* edp table based off of tdiode measurements */
-#define EDP_TEMP_TJ(_index) edp2tj(thermal, z[_index].temperature * 1000)
+#define EDP_TEMP_TJ(_index) (z[_index].temperature * 1000 + therm->edp_offset)
if (temp_tj < EDP_TEMP_TJ(0)) {
lo_limit_edp_tj = temp_low_tj;
hi_limit_edp_tj = EDP_TEMP_TJ(0);
} else if (temp_tj >= EDP_TEMP_TJ(zones_sz-1)) {
lo_limit_edp_tj = EDP_TEMP_TJ(zones_sz-1) -
- thermal->hysteresis_edp;
- hi_limit_edp_tj = thermal->temp_shutdown_tj;
+ therm->hysteresis_edp;
+ hi_limit_edp_tj = dev2tj(device, therm->temp_shutdown);
} else {
for (i = 0; (i + 1) < zones_sz; i++) {
if ((temp_tj >= EDP_TEMP_TJ(i)) &&
(temp_tj < EDP_TEMP_TJ(i+1))) {
lo_limit_edp_tj = EDP_TEMP_TJ(i) -
- thermal->hysteresis_edp;
+ therm->hysteresis_edp;
hi_limit_edp_tj = EDP_TEMP_TJ(i+1);
break;
}
@@ -251,191 +267,242 @@ void tegra_thermal_alert(void *data)
#undef EDP_TEMP_TJ
#else
lo_limit_edp_tj = temp_low_tj;
- hi_limit_edp_tj = thermal->temp_shutdown_tj;
+ hi_limit_edp_tj = dev2tj(device, therm->temp_shutdown);
#endif
/* Get smallest window size */
lo_limit_tj = max(lo_limit_throttle_tj, lo_limit_edp_tj);
hi_limit_tj = min(hi_limit_throttle_tj, hi_limit_edp_tj);
- thermal->device->set_limits(thermal->device->data,
- tj2dev(thermal->device, lo_limit_tj),
- tj2dev(thermal->device, hi_limit_tj));
-
-#ifndef CONFIG_TEGRA_THERMAL_SYSFS
- if (temp_tj >= thermal->temp_throttle_tj) {
- /* start throttling */
- if (!tegra_is_throttling())
- tegra_therm_throttle(true);
- } else if (temp_tj <= thermal->temp_throttle_low_tj) {
- /* switch off throttling */
- if (tegra_is_throttling())
- tegra_therm_throttle(false);
- }
-#endif
+ device->set_limits(device->data,
+ tj2dev(device, lo_limit_tj),
+ tj2dev(device, hi_limit_tj));
#ifdef CONFIG_TEGRA_EDP_LIMITS
/* inform edp governor */
- if (thermal->edp_thermal_zone_val != temp_tj)
- tegra_edp_update_thermal_zone(tj2edp(thermal, temp_tj)/1000);
-
- thermal->edp_thermal_zone_val = temp_tj;
+ if (edp_thermal_zone_val != temp_tj) {
+ long temp_edp = (dev2tj(device, temp_tj) - therm->edp_offset) / 1000;
+ tegra_edp_update_thermal_zone(temp_edp);
+ edp_thermal_zone_val = temp_edp;
+ }
#endif
-
-done:
- mutex_unlock(&thermal_state.mutex);
}
-int tegra_thermal_set_device(struct tegra_thermal_device *device)
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
+/* Make sure this function remains stateless */
+static void tegra_thermal_alert(void *data)
{
-#ifdef CONFIG_TEGRA_THERMAL_SYSFS
- struct thermal_zone_device *thz;
+ mutex_lock(&tegra_therm_mutex);
+ tegra_thermal_alert_unlocked(data);
+ mutex_unlock(&tegra_therm_mutex);
+}
#endif
- /* only support one device */
- if (thermal_state.device)
- return -EINVAL;
-
- thermal_state.device = device;
-
-#ifdef CONFIG_TEGRA_THERMAL_SYSFS
- thz = thermal_zone_device_register(thermal_state.device->name,
- 1, /* trips */
- &thermal_state,
- &tegra_thermal_zone_ops,
- thermal_state.tc1, /* dT/dt */
- thermal_state.tc2, /* throttle */
- thermal_state.passive_delay,
- 0); /* polling delay */
-
- if (IS_ERR(thz)) {
- thz = NULL;
- return -ENODEV;
- }
+#ifdef CONFIG_TEGRA_SKIN_THROTTLE
+static void tegra_skin_thermal_alert(void *data)
+{
+ struct tegra_thermal_device *dev = data;
- thermal_state.thz = thz;
-#endif
- thermal_state.device->set_alert(thermal_state.device->data,
- tegra_thermal_alert,
- &thermal_state);
+ if (!dev->thz->passive)
+ thermal_zone_device_update(dev->thz);
+}
- thermal_state.device->set_shutdown_temp(thermal_state.device->data,
- tj2dev(device, thermal_state.temp_shutdown_tj));
+static int tegra_skin_device_register(struct tegra_thermal_device *device)
+{
+ int i;
+ struct therm_est_subdevice *skin_dev =
+ kzalloc(sizeof(struct therm_est_subdevice), GFP_KERNEL);
+
+ for (i = 0; i < therm->skin_devs_size; i++) {
+ if (therm->skin_devs[i].id == device->id) {
+ memcpy(skin_dev->coeffs,
+ therm->skin_devs[i].coeffs,
+ sizeof(skin_devs[i]->coeffs));
+ break;
+ }
+ }
- /* initialize limits */
- tegra_thermal_alert(&thermal_state);
+ skin_dev->dev_data = device->data;
+ skin_dev->get_temp = device->get_temp;
+
+ skin_devs[skin_devs_count++] = skin_dev;
+
+ /* Create skin thermal device */
+ if (skin_devs_count == therm->skin_devs_size) {
+ struct tegra_thermal_device *thermal_skin_device;
+ struct therm_estimator *skin_estimator;
+
+ skin_estimator = therm_est_register(
+ skin_devs,
+ skin_devs_count,
+ therm->skin_temp_offset,
+ therm->skin_period);
+ thermal_skin_device = kzalloc(sizeof(struct tegra_thermal_device),
+ GFP_KERNEL);
+ thermal_skin_device->name = "skin_pred";
+ thermal_skin_device->id = THERMAL_DEVICE_ID_SKIN;
+ thermal_skin_device->data = skin_estimator;
+ thermal_skin_device->get_temp =
+ (int (*)(void *, long *)) therm_est_get_temp;
+ thermal_skin_device->set_limits =
+ (int (*)(void *, long, long)) therm_est_set_limits;
+ thermal_skin_device->set_alert =
+ (int (*)(void *, void (*)(void *), void *))
+ therm_est_set_alert;
+
+ tegra_thermal_device_register(thermal_skin_device);
+ }
return 0;
}
+#endif
-int __init tegra_thermal_init(struct tegra_thermal_data *data)
+int tegra_thermal_device_register(struct tegra_thermal_device *device)
{
-#ifdef CONFIG_TEGRA_THERMAL_SYSFS
- thermal_state.tc1 = data->tc1;
- thermal_state.tc2 = data->tc2;
- thermal_state.passive_delay = data->passive_delay;
-#else
- thermal_state.temp_throttle_low_tj = data->temp_throttle +
- data->temp_offset -
- data->hysteresis_throttle;
-#endif
- mutex_init(&thermal_state.mutex);
-#ifdef CONFIG_TEGRA_EDP_LIMITS
- thermal_state.edp_offset = data->edp_offset;
- thermal_state.hysteresis_edp = data->hysteresis_edp;
+ struct tegra_thermal_device *dev;
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
+ struct thermal_zone_device *thz;
+ int t1 = 0, t2 = 0, pdelay = 0;
+ bool create_thz = false;
#endif
- thermal_state.temp_throttle_tj = data->temp_throttle +
- data->temp_offset;
- thermal_state.temp_shutdown_tj = data->temp_shutdown +
- data->temp_offset;
- return 0;
-}
+ mutex_lock(&tegra_therm_mutex);
+ list_for_each_entry(dev, &tegra_therm_list, node) {
+ if (dev->id == device->id) {
+ mutex_unlock(&tegra_therm_mutex);
+ return -EINVAL;
+ }
+ }
-int tegra_thermal_exit(void)
-{
-#ifdef CONFIG_TEGRA_THERMAL_SYSFS
- if (thermal_state.thz)
- thermal_zone_device_unregister(thermal_state.thz);
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
+ if (device->id == therm->throttle_edp_device_id) {
+ t1 = therm->tc1;
+ t2 = therm->tc2;
+ pdelay = therm->passive_delay;
+ create_thz = true;
+ }
+#endif
+#ifdef CONFIG_TEGRA_SKIN_THROTTLE
+ if (device->id == therm->skin_device_id) {
+ t1 = 0;
+ t2 = 1;
+ pdelay = 5000;
+ create_thz = true;
+ }
#endif
- return 0;
-}
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
+ if (create_thz) {
+ thz = thermal_zone_device_register(
+ device->name,
+ 1, /* trips */
+ device,
+ &tegra_thermal_zone_ops,
+ t1, /* dT/dt */
+ t2, /* throttle */
+ pdelay,
+ 0); /* polling delay */
+ if (IS_ERR_OR_NULL(thz))
+ return -ENODEV;
+
+ device->thz = thz;
+ }
+#endif
-#ifdef CONFIG_DEBUG_FS
+ list_add(&device->node, &tegra_therm_list);
+ mutex_unlock(&tegra_therm_mutex);
-static int tegra_thermal_throttle_temp_tj_set(void *data, u64 val)
-{
-#ifndef CONFIG_TEGRA_THERMAL_SYSFS
- long throttle_hysteresis = thermal_state.temp_throttle_tj -
- thermal_state.temp_throttle_low_tj;
+ if (device->id == therm->shutdown_device_id) {
+ device->set_shutdown_temp(device->data, therm->temp_shutdown);
+ }
+
+#ifdef CONFIG_TEGRA_SKIN_THROTTLE
+ if (device->id == therm->skin_device_id) {
+ if (create_thz)
+ device->set_alert(device->data,
+ tegra_skin_thermal_alert,
+ device);
+ device->set_limits(device->data, 0, therm->temp_throttle_skin);
+ }
#endif
- mutex_lock(&thermal_state.mutex);
- thermal_state.temp_throttle_tj = val;
-#ifndef CONFIG_TEGRA_THERMAL_SYSFS
- thermal_state.temp_throttle_low_tj = thermal_state.temp_throttle_tj -
- throttle_hysteresis;
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
+ if (device->id == therm->throttle_edp_device_id) {
+ device->set_alert(device->data, tegra_thermal_alert, device);
+
+ /* initialize limits */
+ tegra_thermal_alert(device);
+ }
#endif
- mutex_unlock(&thermal_state.mutex);
- tegra_thermal_alert(&thermal_state);
+#ifdef CONFIG_TEGRA_SKIN_THROTTLE
+ if ((therm->skin_device_id == THERMAL_DEVICE_ID_SKIN) &&
+ device->id && skin_devs_bitmap)
+ tegra_skin_device_register(device);
+#endif
+ register_pm_notifier(&tegra_thermal_nb);
return 0;
}
-static int tegra_thermal_throttle_temp_tj_get(void *data, u64 *val)
+/* This needs to be inialized later hand */
+static int __init throttle_list_init(void)
{
- *val = (u64)thermal_state.temp_throttle_tj;
+ int i;
+ for (i = 0; i < throttle_list_size; i++)
+ if (balanced_throttle_register(&throttle_list[i]))
+ return -ENODEV;
+
return 0;
}
+late_initcall(throttle_list_init);
-DEFINE_SIMPLE_ATTRIBUTE(throttle_temp_tj_fops,
- tegra_thermal_throttle_temp_tj_get,
- tegra_thermal_throttle_temp_tj_set,
- "%llu\n");
-
-static int tegra_thermal_shutdown_temp_tj_set(void *data, u64 val)
+int __init tegra_thermal_init(struct tegra_thermal_data *data,
+ struct balanced_throttle *tlist,
+ int tlist_size)
{
- thermal_state.temp_shutdown_tj = val;
+ therm = data;
+#ifdef CONFIG_DEBUG_FS
+ thermal_debugfs_root = debugfs_create_dir("tegra_thermal", 0);
+#endif
- if (thermal_state.device)
- thermal_state.device->set_shutdown_temp(
- thermal_state.device->data,
- tj2dev(thermal_state.device,
- thermal_state.temp_shutdown_tj));
+#ifdef CONFIG_TEGRA_SKIN_THROTTLE
+ {
+ int i;
+ for (i = 0; i < therm->skin_devs_size; i++)
+ skin_devs_bitmap |= therm->skin_devs[i].id;
+ }
+#endif
- tegra_thermal_alert(&thermal_state);
+ throttle_list = tlist;
+ throttle_list_size = tlist_size;
return 0;
}
-static int tegra_thermal_shutdown_temp_tj_get(void *data, u64 *val)
+int tegra_thermal_exit(void)
{
- *val = (u64)thermal_state.temp_shutdown_tj;
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
+ struct tegra_thermal_device *dev;
+ mutex_lock(&tegra_therm_mutex);
+ list_for_each_entry(dev, &tegra_therm_list, node) {
+ thermal_zone_device_unregister(dev->thz);
+ }
+ mutex_unlock(&tegra_therm_mutex);
+#endif
+
return 0;
}
-DEFINE_SIMPLE_ATTRIBUTE(shutdown_temp_tj_fops,
- tegra_thermal_shutdown_temp_tj_get,
- tegra_thermal_shutdown_temp_tj_set,
- "%llu\n");
-
-
+#ifdef CONFIG_DEBUG_FS
static int tegra_thermal_temp_tj_get(void *data, u64 *val)
{
- long temp_tj, temp_dev;
-
- if (thermal_state.device) {
- thermal_state.device->get_temp(thermal_state.device->data,
- &temp_dev);
+ long temp_tj;
- /* Convert all temps to tj and then do all work/logic in
- terms of tj in order to avoid confusion */
- temp_tj = dev2tj(thermal_state.device, temp_dev);
- } else {
+ mutex_lock(&tegra_therm_mutex);
+ if (tegra_thermal_get_temp_unlocked(&temp_tj, false))
temp_tj = -1;
- }
+ mutex_unlock(&tegra_therm_mutex);
*val = (u64)temp_tj;
@@ -447,98 +514,101 @@ DEFINE_SIMPLE_ATTRIBUTE(temp_tj_fops,
NULL,
"%llu\n");
-#ifdef CONFIG_TEGRA_THERMAL_SYSFS
-static int tegra_thermal_tc1_set(void *data, u64 val)
+static int __init temp_tj_debug_init(void)
{
- thermal_state.thz->tc1 = val;
+ debugfs_create_file("temp_tj", 0644, thermal_debugfs_root,
+ NULL, &temp_tj_fops);
return 0;
}
-
-static int tegra_thermal_tc1_get(void *data, u64 *val)
-{
- *val = (u64)thermal_state.thz->tc1;
- return 0;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(tc1_fops,
- tegra_thermal_tc1_get,
- tegra_thermal_tc1_set,
- "%llu\n");
-
-static int tegra_thermal_tc2_set(void *data, u64 val)
-{
- thermal_state.thz->tc2 = val;
- return 0;
-}
-
-static int tegra_thermal_tc2_get(void *data, u64 *val)
-{
- *val = (u64)thermal_state.thz->tc2;
- return 0;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(tc2_fops,
- tegra_thermal_tc2_get,
- tegra_thermal_tc2_set,
- "%llu\n");
-
-static int tegra_thermal_passive_delay_set(void *data, u64 val)
-{
- thermal_state.thz->passive_delay = val;
- return 0;
-}
-
-static int tegra_thermal_passive_delay_get(void *data, u64 *val)
-{
- *val = (u64)thermal_state.thz->passive_delay;
- return 0;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(passive_delay_fops,
- tegra_thermal_passive_delay_get,
- tegra_thermal_passive_delay_set,
- "%llu\n");
+late_initcall(temp_tj_debug_init);
+
+
+#define TEGRA_THERM_DEBUGFS(_name, _device_id, throttle, shutdown) \
+ static int tegra_thermal_##_name##_set(void *data, u64 val) \
+ { \
+ struct tegra_thermal_device *dev; \
+ mutex_lock(&tegra_therm_mutex); \
+ therm->_name = val; \
+ list_for_each_entry(dev, &tegra_therm_list, node) \
+ if (dev->id == therm->_device_id) \
+ break; \
+ if (dev) { \
+ if (throttle) \
+ tegra_thermal_alert_unlocked(dev); \
+ if (shutdown) \
+ dev->set_shutdown_temp(dev->data, \
+ therm->temp_shutdown); \
+ } \
+ mutex_unlock(&tegra_therm_mutex); \
+ return 0; \
+ } \
+ static int tegra_thermal_##_name##_get(void *data, u64 *val) \
+ { \
+ *val = (u64)therm->_name; \
+ return 0; \
+ } \
+ DEFINE_SIMPLE_ATTRIBUTE(_name##_fops, \
+ tegra_thermal_##_name##_get, \
+ tegra_thermal_##_name##_set, \
+ "%llu\n"); \
+ static int __init _name##_debug_init(void) \
+ { \
+ debugfs_create_file(#_name, 0644, thermal_debugfs_root, \
+ NULL, &_name##_fops); \
+ return 0; \
+ } \
+ late_initcall(_name##_debug_init);
+
+
+TEGRA_THERM_DEBUGFS(temp_shutdown, shutdown_device_id, false, true);
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
+TEGRA_THERM_DEBUGFS(temp_throttle, throttle_edp_device_id, true, false);
#endif
-
-
-static struct dentry *thermal_debugfs_root;
-
-static int __init tegra_thermal_debug_init(void)
-{
- thermal_debugfs_root = debugfs_create_dir("tegra_thermal", 0);
-
- if (!debugfs_create_file("throttle_temp_tj", 0644, thermal_debugfs_root,
- NULL, &throttle_temp_tj_fops))
- goto err_out;
-
- if (!debugfs_create_file("shutdown_temp_tj", 0644, thermal_debugfs_root,
- NULL, &shutdown_temp_tj_fops))
- goto err_out;
-
- if (!debugfs_create_file("temp_tj", 0644, thermal_debugfs_root,
- NULL, &temp_tj_fops))
- goto err_out;
-
-#ifdef CONFIG_TEGRA_THERMAL_SYSFS
- if (!debugfs_create_file("tc1", 0644, thermal_debugfs_root,
- NULL, &tc1_fops))
- goto err_out;
-
- if (!debugfs_create_file("tc2", 0644, thermal_debugfs_root,
- NULL, &tc2_fops))
- goto err_out;
-
- if (!debugfs_create_file("passive_delay", 0644, thermal_debugfs_root,
- NULL, &passive_delay_fops))
- goto err_out;
+#ifdef CONFIG_TEGRA_SKIN_THROTTLE
+TEGRA_THERM_DEBUGFS(temp_throttle_skin, skin_device_id, false, false);
#endif
- return 0;
-
-err_out:
- debugfs_remove_recursive(thermal_debugfs_root);
- return -ENOMEM;
-}
-
-late_initcall(tegra_thermal_debug_init);
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
+#define THERM_DEBUGFS(_name) \
+ static int tegra_thermal_##_name##_set(void *data, u64 val) \
+ { \
+ struct tegra_thermal_device *dev; \
+ mutex_lock(&tegra_therm_mutex); \
+ list_for_each_entry(dev, &tegra_therm_list, node) \
+ if (dev->id == therm->throttle_edp_device_id) \
+ break; \
+ if (dev) \
+ dev->thz->_name = val; \
+ mutex_unlock(&tegra_therm_mutex); \
+ return 0; \
+ } \
+ static int tegra_thermal_##_name##_get(void *data, u64 *val) \
+ { \
+ struct tegra_thermal_device *dev; \
+ mutex_lock(&tegra_therm_mutex); \
+ list_for_each_entry(dev, &tegra_therm_list, node) \
+ if (dev->id == therm->throttle_edp_device_id) \
+ break; \
+ if (dev) \
+ *val = (u64)dev->thz->_name; \
+ mutex_unlock(&tegra_therm_mutex); \
+ return 0; \
+ } \
+ DEFINE_SIMPLE_ATTRIBUTE(_name##_fops, \
+ tegra_thermal_##_name##_get, \
+ tegra_thermal_##_name##_set, \
+ "%llu\n"); \
+ static int __init _name##_debug_init(void) \
+ { \
+ debugfs_create_file(#_name, 0644, thermal_debugfs_root, \
+ NULL, &_name##_fops); \
+ return 0; \
+ } \
+ late_initcall(_name##_debug_init);
+
+
+THERM_DEBUGFS(tc1);
+THERM_DEBUGFS(tc2);
+THERM_DEBUGFS(passive_delay);
+#endif
#endif
diff --git a/arch/arm/mach-tegra/tegra3_throttle.c b/arch/arm/mach-tegra/tegra3_throttle.c
index f927be7800d6..d980144ed052 100644
--- a/arch/arm/mach-tegra/tegra3_throttle.c
+++ b/arch/arm/mach-tegra/tegra3_throttle.c
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/tegra3_throttle.c
*
- * Copyright (c) 2011, NVIDIA Corporation.
+ * 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 as published by
@@ -27,44 +27,27 @@
#include <linux/seq_file.h>
#include <linux/uaccess.h>
#include <linux/thermal.h>
+#include <mach/thermal.h>
#include "clock.h"
#include "cpu-tegra.h"
#include "dvfs.h"
-/* tegra throttling require frequencies in the table to be in ascending order */
-static struct cpufreq_frequency_table *cpu_freq_table;
static struct mutex *cpu_throttle_lock;
-
-static struct {
- unsigned int cpu_freq;
- int core_cap_level;
- int ms;
-} throttle_table[] = {
- { 0, 1000, 2000 }, /* placeholder for cpu floor rate */
- { 640000, 1000, 2000 },
- { 640000, 1000, 2000 },
- { 640000, 1000, 2000 },
- { 640000, 1000, 2000 },
- { 640000, 1000, 2000 },
- { 760000, 1000, 2000 },
- { 760000, 1050, 2000 },
- {1000000, 1050, 2000 },
- {1000000, 1100, 2000 },
-};
-
-static int is_throttling;
-static int throttle_index;
-static struct delayed_work throttle_work;
-static struct workqueue_struct *workqueue;
-static DEFINE_MUTEX(tegra_throttle_lock);
-#ifdef CONFIG_TEGRA_THERMAL_SYSFS
-static struct thermal_cooling_device *cdev;
-#endif
+static DEFINE_MUTEX(bthrot_list_lock);
+static LIST_HEAD(bthrot_list);
static unsigned int clip_to_table(unsigned int cpu_freq)
{
int i;
+ struct cpufreq_frequency_table *cpu_freq_table;
+ struct tegra_cpufreq_table_data *table_data =
+ tegra_cpufreq_table_get();
+
+ if (IS_ERR_OR_NULL(table_data))
+ return -EINVAL;
+
+ cpu_freq_table = table_data->freq_table;
for (i = 0; cpu_freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
if (cpu_freq_table[i].frequency > cpu_freq)
@@ -74,100 +57,69 @@ static unsigned int clip_to_table(unsigned int cpu_freq)
return cpu_freq_table[i].frequency;
}
-static void tegra_throttle_work_func(struct work_struct *work)
-{
- unsigned int cpu_freq;
- int core_level;
-
- mutex_lock(cpu_throttle_lock);
- if (!is_throttling) {
- mutex_unlock(cpu_throttle_lock);
- return;
- }
-
- cpu_freq = tegra_getspeed(0);
- throttle_index -= throttle_index ? 1 : 0;
-
- core_level = throttle_table[throttle_index].core_cap_level;
- if (throttle_table[throttle_index].cpu_freq < cpu_freq)
- tegra_cpu_set_speed_cap(NULL);
-
- if (throttle_index || (throttle_table[0].cpu_freq < cpu_freq))
- queue_delayed_work(workqueue, &throttle_work,
- msecs_to_jiffies(throttle_table[throttle_index].ms));
-
- mutex_unlock(cpu_throttle_lock);
-
- tegra_dvfs_core_cap_level_set(core_level);
-}
-
-/*
- * tegra_throttling_enable
- * This function may sleep
- */
-void tegra_throttling_enable(bool enable)
+unsigned int tegra_throttle_governor_speed(unsigned int requested_speed)
{
- mutex_lock(&tegra_throttle_lock);
- mutex_lock(cpu_throttle_lock);
-
- if (enable && !(is_throttling++)) {
- int core_level;
- unsigned int cpu_freq = tegra_getspeed(0);
- throttle_index = ARRAY_SIZE(throttle_table) - 1;
+ struct balanced_throttle *bthrot;
+ unsigned int throttle_speed = requested_speed;
+ int index;
+ unsigned int bthrot_speed;
+ unsigned int lowest_speed;
+ struct cpufreq_frequency_table *cpu_freq_table;
+ struct tegra_cpufreq_table_data *table_data =
+ tegra_cpufreq_table_get();
- core_level = throttle_table[throttle_index].core_cap_level;
- if (throttle_table[throttle_index].cpu_freq < cpu_freq)
- tegra_cpu_set_speed_cap(NULL);
+ if (!table_data)
+ return requested_speed;
- queue_delayed_work(workqueue, &throttle_work,
- msecs_to_jiffies(throttle_table[throttle_index].ms));
- mutex_unlock(cpu_throttle_lock);
+ cpu_freq_table = table_data->freq_table;
+ lowest_speed = cpu_freq_table[table_data->throttle_lowest_index].frequency;
- tegra_dvfs_core_cap_level_set(core_level);
- tegra_dvfs_core_cap_enable(true);
+ mutex_lock(&bthrot_list_lock);
- mutex_unlock(&tegra_throttle_lock);
- return;
- }
+ list_for_each_entry(bthrot, &bthrot_list, node) {
+ if (bthrot->is_throttling) {
+ index = bthrot->throttle_index;
+ bthrot_speed = bthrot->throt_tab[index].cpu_freq;
- if (!enable && is_throttling) {
- if (!(--is_throttling)) {
- /* restore speed requested by governor */
- tegra_cpu_set_speed_cap(NULL);
- mutex_unlock(cpu_throttle_lock);
+ if (bthrot_speed == 0)
+ bthrot_speed = lowest_speed;
+ else
+ bthrot_speed = clip_to_table(bthrot_speed);
- tegra_dvfs_core_cap_enable(false);
- cancel_delayed_work_sync(&throttle_work);
- mutex_unlock(&tegra_throttle_lock);
- return;
+ throttle_speed = min(throttle_speed, bthrot_speed);
}
}
+ mutex_unlock(&bthrot_list_lock);
- mutex_unlock(cpu_throttle_lock);
- mutex_unlock(&tegra_throttle_lock);
-}
-EXPORT_SYMBOL_GPL(tegra_throttling_enable);
-
-unsigned int tegra_throttle_governor_speed(unsigned int requested_speed)
-{
- return is_throttling ?
- min(requested_speed, throttle_table[throttle_index].cpu_freq) :
- requested_speed;
+ return throttle_speed;
}
bool tegra_is_throttling(void)
{
+ struct balanced_throttle *bthrot;
+ bool is_throttling = false;
+
+ mutex_lock(&bthrot_list_lock);
+ list_for_each_entry(bthrot, &bthrot_list, node) {
+ if (bthrot->is_throttling) {
+ is_throttling = true;
+ break;
+ }
+ }
+ mutex_unlock(&bthrot_list_lock);
+
return is_throttling;
}
-#ifdef CONFIG_TEGRA_THERMAL_SYSFS
-
static int
tegra_throttle_get_max_state(struct thermal_cooling_device *cdev,
unsigned long *max_state)
{
- *max_state = ARRAY_SIZE(throttle_table);
+ struct balanced_throttle *bthrot = cdev->devdata;
+
+ *max_state = bthrot->throt_tab_size;
+
return 0;
}
@@ -175,9 +127,11 @@ static int
tegra_throttle_get_cur_state(struct thermal_cooling_device *cdev,
unsigned long *cur_state)
{
+ struct balanced_throttle *bthrot = cdev->devdata;
+
mutex_lock(cpu_throttle_lock);
- *cur_state = is_throttling ?
- (ARRAY_SIZE(throttle_table) - throttle_index) :
+ *cur_state = bthrot->is_throttling ?
+ (bthrot->throt_tab_size - bthrot->throttle_index) :
0;
mutex_unlock(cpu_throttle_lock);
@@ -188,25 +142,28 @@ static int
tegra_throttle_set_cur_state(struct thermal_cooling_device *cdev,
unsigned long cur_state)
{
+ struct balanced_throttle *bthrot = cdev->devdata;
int core_level;
+ int index;
mutex_lock(cpu_throttle_lock);
if (cur_state == 0) {
/* restore speed requested by governor */
- if (is_throttling) {
+ if (bthrot->is_throttling) {
tegra_dvfs_core_cap_enable(false);
- is_throttling = false;
+ bthrot->is_throttling = false;
}
tegra_cpu_set_speed_cap(NULL);
} else {
- if (!is_throttling) {
+ if (!bthrot->is_throttling) {
tegra_dvfs_core_cap_enable(true);
- is_throttling = true;
+ bthrot->is_throttling = true;
}
- throttle_index = ARRAY_SIZE(throttle_table) - cur_state;
- core_level = throttle_table[throttle_index].core_cap_level;
+ bthrot->throttle_index = bthrot->throt_tab_size - cur_state;
+ index = bthrot->throttle_index;
+ core_level = bthrot->throt_tab[index].core_cap_level;
tegra_dvfs_core_cap_level_set(core_level);
tegra_cpu_set_speed_cap(NULL);
@@ -217,88 +174,23 @@ tegra_throttle_set_cur_state(struct thermal_cooling_device *cdev,
return 0;
}
-struct thermal_cooling_device_ops tegra_throttle_cooling_ops = {
+static struct thermal_cooling_device_ops tegra_throttle_cooling_ops = {
.get_max_state = tegra_throttle_get_max_state,
.get_cur_state = tegra_throttle_get_cur_state,
.set_cur_state = tegra_throttle_set_cur_state,
};
-#endif
-
-int __init tegra_throttle_init(struct mutex *cpu_lock)
-{
- int i;
- struct tegra_cpufreq_table_data *table_data =
- tegra_cpufreq_table_get();
- if (IS_ERR_OR_NULL(table_data))
- return -EINVAL;
-
- /*
- * High-priority, others flags default: not bound to a specific
- * CPU, has rescue worker task (in case of allocation deadlock,
- * etc.). Single-threaded.
- */
- workqueue = alloc_workqueue("cpu-tegra",
- WQ_HIGHPRI | WQ_UNBOUND | WQ_RESCUER, 1);
- if (!workqueue)
- return -ENOMEM;
- INIT_DELAYED_WORK(&throttle_work, tegra_throttle_work_func);
-
- cpu_throttle_lock = cpu_lock;
- cpu_freq_table = table_data->freq_table;
- throttle_table[0].cpu_freq =
- cpu_freq_table[table_data->throttle_lowest_index].frequency;
-
- for (i = 0; i < ARRAY_SIZE(throttle_table); i++) {
- unsigned int cpu_freq = throttle_table[i].cpu_freq;
- throttle_table[i].cpu_freq = clip_to_table(cpu_freq);
- }
-
-#ifdef CONFIG_TEGRA_THERMAL_SYSFS
- cdev = thermal_cooling_device_register("Throttle", NULL,
- &tegra_throttle_cooling_ops);
-
- if (IS_ERR(cdev)) {
- cdev = NULL;
- return -ENODEV;
- }
-#endif
-
- return 0;
-}
-
-void tegra_throttle_exit(void)
-{
-#ifdef CONFIG_TEGRA_THERMAL_SYSFS
- if (cdev) {
- thermal_cooling_device_unregister(cdev);
- cdev = NULL;
- }
-#endif
- destroy_workqueue(workqueue);
-}
#ifdef CONFIG_DEBUG_FS
-
-static int throttle_debug_set(void *data, u64 val)
-{
- tegra_throttling_enable(val);
- return 0;
-}
-static int throttle_debug_get(void *data, u64 *val)
-{
- *val = (u64) is_throttling;
- return 0;
-}
-DEFINE_SIMPLE_ATTRIBUTE(throttle_fops, throttle_debug_get, throttle_debug_set,
- "%llu\n");
static int table_show(struct seq_file *s, void *data)
{
+ struct balanced_throttle *bthrot = s->private;
int i;
- for (i = 0; i < ARRAY_SIZE(throttle_table); i++)
- seq_printf(s, "[%d] = %7u %4d %5d\n",
- i, throttle_table[i].cpu_freq,
- throttle_table[i].core_cap_level, throttle_table[i].ms);
+ for (i = 0; i < bthrot->throt_tab_size; i++)
+ seq_printf(s, "[%d] = %7u %4d\n",
+ i, bthrot->throt_tab[i].cpu_freq,
+ bthrot->throt_tab[i].core_cap_level);
+
return 0;
}
@@ -310,11 +202,11 @@ static int table_open(struct inode *inode, struct file *file)
static ssize_t table_write(struct file *file,
const char __user *userbuf, size_t count, loff_t *ppos)
{
+ struct balanced_throttle *bthrot = file->private_data;
char buf[80];
int table_idx;
unsigned int cpu_freq;
int core_cap_level;
- int ms;
if (sizeof(buf) <= count)
return -EINVAL;
@@ -327,17 +219,16 @@ static ssize_t table_write(struct file *file,
buf[count] = '\0';
strim(buf);
- if (sscanf(buf, "[%d] = %u %d %d",
- &table_idx, &cpu_freq, &core_cap_level, &ms) != 4)
+ if (sscanf(buf, "[%d] = %u %d",
+ &table_idx, &cpu_freq, &core_cap_level) != 3)
return -1;
- if ((table_idx < 0) || (table_idx >= ARRAY_SIZE(throttle_table)))
+ if ((table_idx < 0) || (table_idx >= bthrot->throt_tab_size))
return -EINVAL;
/* round new settings before updating table */
- throttle_table[table_idx].cpu_freq = clip_to_table(cpu_freq);
- throttle_table[table_idx].core_cap_level = (core_cap_level / 50) * 50;
- throttle_table[table_idx].ms = jiffies_to_msecs(msecs_to_jiffies(ms));
+ bthrot->throt_tab[table_idx].cpu_freq = clip_to_table(cpu_freq);
+ bthrot->throt_tab[table_idx].core_cap_level = (core_cap_level / 50) * 50;
return count;
}
@@ -350,18 +241,61 @@ static const struct file_operations table_fops = {
.release = single_release,
};
+static struct dentry *throttle_debugfs_root;
+#endif /* CONFIG_DEBUG_FS */
+
-int __init tegra_throttle_debug_init(struct dentry *cpu_tegra_debugfs_root)
+int balanced_throttle_register(struct balanced_throttle *bthrot)
{
- if (!debugfs_create_file("throttle", 0644, cpu_tegra_debugfs_root,
- NULL, &throttle_fops))
- return -ENOMEM;
+#ifdef CONFIG_DEBUG_FS
+ char name[32];
+#endif
+ struct balanced_throttle *dev;
+
+ mutex_lock(&bthrot_list_lock);
+ list_for_each_entry(dev, &bthrot_list, node) {
+ if (dev->id == bthrot->id) {
+ mutex_unlock(&bthrot_list_lock);
+ return -EINVAL;
+ }
+ }
+
- if (!debugfs_create_file("throttle_table", 0644, cpu_tegra_debugfs_root,
- NULL, &table_fops))
- return -ENOMEM;
+ list_add(&bthrot->node, &bthrot_list);
+ mutex_unlock(&bthrot_list_lock);
+
+ bthrot->cdev = thermal_cooling_device_register(
+ "balanced",
+ bthrot,
+ &tegra_throttle_cooling_ops);
+
+ if (IS_ERR(bthrot->cdev)) {
+ bthrot->cdev = NULL;
+ return -ENODEV;
+ }
+
+#ifdef CONFIG_DEBUG_FS
+ sprintf(name, "throttle_table%d", bthrot->id);
+ debugfs_create_file(name,0644, throttle_debugfs_root,
+ bthrot, &table_fops);
+#endif
return 0;
}
-#endif /* CONFIG_DEBUG_FS */
+
+int __init tegra_throttle_init(struct mutex *cpu_lock)
+{
+ cpu_throttle_lock = cpu_lock;
+#ifdef CONFIG_DEBUG_FS
+ throttle_debugfs_root = debugfs_create_dir("tegra_throttle", 0);
+#endif
+ return 0;
+}
+
+void tegra_throttle_exit(void)
+{
+#ifdef CONFIG_DEBUG_FS
+ debugfs_remove_recursive(throttle_debugfs_root);
+#endif
+}
diff --git a/arch/arm/mach-tegra/tegra3_tsensor.c b/arch/arm/mach-tegra/tegra3_tsensor.c
index 01d3cd7ec627..7a1c122099bc 100644
--- a/arch/arm/mach-tegra/tegra3_tsensor.c
+++ b/arch/arm/mach-tegra/tegra3_tsensor.c
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/tegra3_tsensor.c
*
- * Copyright (C) 2011 NVIDIA Corporation.
+ * Copyright (C) 2011-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
@@ -107,6 +107,7 @@ static void tegra3_tsensor_probe_callback(struct tegra_tsensor_data *data)
thermal_device->name = "tsensor";
thermal_device->data = data;
+ thermal_device->id = THERMAL_DEVICE_ID_TSENSOR;
thermal_device->offset = TSENSOR_OFFSET;
thermal_device->get_temp = tsensor_get_temp;
thermal_device->get_temp_low = tsensor_get_temp_low;
@@ -114,7 +115,8 @@ static void tegra3_tsensor_probe_callback(struct tegra_tsensor_data *data)
thermal_device->set_alert = tsensor_set_alert;
thermal_device->set_shutdown_temp = tsensor_set_shutdown_temp;
- if (tegra_thermal_set_device(thermal_device)) /* This should not fail */
+ /* This should not fail */
+ if (tegra_thermal_device_register(thermal_device))
BUG();
}
diff --git a/arch/arm/mach-tegra/tegra3_usb_phy.c b/arch/arm/mach-tegra/tegra3_usb_phy.c
new file mode 100644
index 000000000000..3a831c59a750
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra3_usb_phy.c
@@ -0,0 +1,2870 @@
+/*
+ * arch/arm/mach-tegra/tegra3_usb_phy.c
+ *
+ * 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
+ * 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/resource.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/platform_data/tegra_usb.h>
+#include <mach/clk.h>
+#include <mach/iomap.h>
+#include <mach/pinmux.h>
+#include "tegra_usb_phy.h"
+#include "gpio-names.h"
+#include "fuse.h"
+
+#define USB_USBCMD 0x130
+#define USB_USBCMD_RS (1 << 0)
+#define USB_CMD_RESET (1<<1)
+
+#define USB_USBSTS 0x134
+#define USB_USBSTS_PCI (1 << 2)
+#define USB_USBSTS_SRI (1 << 7)
+#define USB_USBSTS_HCH (1 << 12)
+
+#define USB_USBINTR 0x138
+
+#define USB_TXFILLTUNING 0x154
+#define USB_FIFO_TXFILL_THRES(x) (((x) & 0x1f) << 16)
+#define USB_FIFO_TXFILL_MASK 0x1f0000
+
+#define USB_ASYNCLISTADDR 0x148
+
+#define ICUSB_CTRL 0x15c
+
+#define USB_PORTSC 0x174
+#define USB_PORTSC_WKOC (1 << 22)
+#define USB_PORTSC_WKDS (1 << 21)
+#define USB_PORTSC_WKCN (1 << 20)
+#define USB_PORTSC_PTC(x) (((x) & 0xf) << 16)
+#define USB_PORTSC_PP (1 << 12)
+#define USB_PORTSC_LS(x) (((x) & 0x3) << 10)
+#define USB_PORTSC_SUSP (1 << 7)
+#define USB_PORTSC_RESUME (1 << 6)
+#define USB_PORTSC_OCC (1 << 5)
+#define USB_PORTSC_PEC (1 << 3)
+#define USB_PORTSC_PE (1 << 2)
+#define USB_PORTSC_CSC (1 << 1)
+#define USB_PORTSC_CCS (1 << 0)
+#define USB_PORTSC_RWC_BITS (USB_PORTSC_CSC | USB_PORTSC_PEC | USB_PORTSC_OCC)
+
+#define HOSTPC1_DEVLC 0x1b4
+#define HOSTPC1_DEVLC_PHCD (1 << 22)
+#define HOSTPC1_DEVLC_PTS(x) (((x) & 0x7) << 29)
+#define HOSTPC1_DEVLC_PTS_MASK 7
+#define HOSTPC1_DEVLC_PTS_HSIC 4
+#define HOSTPC1_DEVLC_STS (1 << 28)
+#define HOSTPC1_DEVLC_PSPD(x) (((x) & 0x3) << 25)
+#define HOSTPC1_DEVLC_PSPD_MASK 3
+#define HOSTPC1_DEVLC_PSPD_HIGH_SPEED 2
+
+#define USB_USBMODE 0x1f8
+#define USB_USBMODE_MASK (3 << 0)
+#define USB_USBMODE_HOST (3 << 0)
+#define USB_USBMODE_DEVICE (2 << 0)
+
+#define USB_SUSP_CTRL 0x400
+#define USB_WAKE_ON_CNNT_EN_DEV (1 << 3)
+#define USB_WAKE_ON_DISCON_EN_DEV (1 << 4)
+#define USB_SUSP_CLR (1 << 5)
+#define USB_PHY_CLK_VALID (1 << 7)
+#define USB_PHY_CLK_VALID_INT_ENB (1 << 9)
+#define USB_PHY_CLK_VALID_INT_STS (1 << 8)
+#define UTMIP_RESET (1 << 11)
+#define UTMIP_PHY_ENABLE (1 << 12)
+#define ULPI_PHY_ENABLE (1 << 13)
+#define UHSIC_RESET (1 << 14)
+#define USB_WAKEUP_DEBOUNCE_COUNT(x) (((x) & 0x7) << 16)
+#define UHSIC_PHY_ENABLE (1 << 19)
+#define ULPIS2S_SLV0_RESET (1 << 20)
+#define ULPIS2S_SLV1_RESET (1 << 21)
+#define ULPIS2S_LINE_RESET (1 << 22)
+#define ULPI_PADS_RESET (1 << 23)
+#define ULPI_PADS_CLKEN_RESET (1 << 24)
+
+#define USB_PHY_VBUS_WAKEUP_ID 0x408
+#define VDAT_DET_INT_EN (1 << 16)
+#define VDAT_DET_CHG_DET (1 << 17)
+#define VDAT_DET_STS (1 << 18)
+#define USB_ID_STATUS (1 << 2)
+
+#define ULPIS2S_CTRL 0x418
+#define ULPIS2S_ENA (1 << 0)
+#define ULPIS2S_SUPPORT_DISCONNECT (1 << 2)
+#define ULPIS2S_PLLU_MASTER_BLASTER60 (1 << 3)
+#define ULPIS2S_SPARE(x) (((x) & 0xF) << 8)
+#define ULPIS2S_FORCE_ULPI_CLK_OUT (1 << 12)
+#define ULPIS2S_DISCON_DONT_CHECK_SE0 (1 << 13)
+#define ULPIS2S_SUPPORT_HS_KEEP_ALIVE (1 << 14)
+#define ULPIS2S_DISABLE_STP_PU (1 << 15)
+#define ULPIS2S_SLV0_CLAMP_XMIT (1 << 16)
+
+#define ULPI_TIMING_CTRL_0 0x424
+#define ULPI_CLOCK_OUT_DELAY(x) ((x) & 0x1F)
+#define ULPI_OUTPUT_PINMUX_BYP (1 << 10)
+#define ULPI_CLKOUT_PINMUX_BYP (1 << 11)
+#define ULPI_SHADOW_CLK_LOOPBACK_EN (1 << 12)
+#define ULPI_SHADOW_CLK_SEL (1 << 13)
+#define ULPI_CORE_CLK_SEL (1 << 14)
+#define ULPI_SHADOW_CLK_DELAY(x) (((x) & 0x1F) << 16)
+#define ULPI_LBK_PAD_EN (1 << 26)
+#define ULPI_LBK_PAD_E_INPUT_OR (1 << 27)
+#define ULPI_CLK_OUT_ENA (1 << 28)
+#define ULPI_CLK_PADOUT_ENA (1 << 29)
+
+#define ULPI_TIMING_CTRL_1 0x428
+#define ULPI_DATA_TRIMMER_LOAD (1 << 0)
+#define ULPI_DATA_TRIMMER_SEL(x) (((x) & 0x7) << 1)
+#define ULPI_STPDIRNXT_TRIMMER_LOAD (1 << 16)
+#define ULPI_STPDIRNXT_TRIMMER_SEL(x) (((x) & 0x7) << 17)
+#define ULPI_DIR_TRIMMER_LOAD (1 << 24)
+#define ULPI_DIR_TRIMMER_SEL(x) (((x) & 0x7) << 25)
+
+#define UTMIP_XCVR_CFG0 0x808
+#define UTMIP_XCVR_SETUP(x) (((x) & 0xf) << 0)
+#define UTMIP_XCVR_LSRSLEW(x) (((x) & 0x3) << 8)
+#define UTMIP_XCVR_LSFSLEW(x) (((x) & 0x3) << 10)
+#define UTMIP_FORCE_PD_POWERDOWN (1 << 14)
+#define UTMIP_FORCE_PD2_POWERDOWN (1 << 16)
+#define UTMIP_FORCE_PDZI_POWERDOWN (1 << 18)
+#define UTMIP_XCVR_LSBIAS_SEL (1 << 21)
+#define UTMIP_XCVR_SETUP_MSB(x) (((x) & 0x7) << 22)
+#define UTMIP_XCVR_HSSLEW_MSB(x) (((x) & 0x7f) << 25)
+#define UTMIP_XCVR_MAX_OFFSET 2
+#define UTMIP_XCVR_SETUP_MAX_VALUE 0x7f
+#define UTMIP_XCVR_SETUP_MIN_VALUE 0
+#define XCVR_SETUP_MSB_CALIB(x) ((x) >> 4)
+
+#define UTMIP_BIAS_CFG0 0x80c
+#define UTMIP_OTGPD (1 << 11)
+#define UTMIP_BIASPD (1 << 10)
+#define UTMIP_HSSQUELCH_LEVEL(x) (((x) & 0x3) << 0)
+#define UTMIP_HSDISCON_LEVEL(x) (((x) & 0x3) << 2)
+#define UTMIP_HSDISCON_LEVEL_MSB (1 << 24)
+
+#define UTMIP_HSRX_CFG0 0x810
+#define UTMIP_ELASTIC_LIMIT(x) (((x) & 0x1f) << 10)
+#define UTMIP_IDLE_WAIT(x) (((x) & 0x1f) << 15)
+
+#define UTMIP_HSRX_CFG1 0x814
+#define UTMIP_HS_SYNC_START_DLY(x) (((x) & 0x1f) << 1)
+
+#define UTMIP_TX_CFG0 0x820
+#define UTMIP_FS_PREABMLE_J (1 << 19)
+#define UTMIP_HS_DISCON_DISABLE (1 << 8)
+
+#define UTMIP_DEBOUNCE_CFG0 0x82c
+#define UTMIP_BIAS_DEBOUNCE_A(x) (((x) & 0xffff) << 0)
+
+#define UTMIP_BAT_CHRG_CFG0 0x830
+#define UTMIP_PD_CHRG (1 << 0)
+#define UTMIP_ON_SINK_EN (1 << 2)
+#define UTMIP_OP_SRC_EN (1 << 3)
+
+#define UTMIP_XCVR_CFG1 0x838
+#define UTMIP_FORCE_PDDISC_POWERDOWN (1 << 0)
+#define UTMIP_FORCE_PDCHRP_POWERDOWN (1 << 2)
+#define UTMIP_FORCE_PDDR_POWERDOWN (1 << 4)
+#define UTMIP_XCVR_TERM_RANGE_ADJ(x) (((x) & 0xf) << 18)
+
+#define UTMIP_BIAS_CFG1 0x83c
+#define UTMIP_BIAS_PDTRK_COUNT(x) (((x) & 0x1f) << 3)
+#define UTMIP_BIAS_PDTRK_POWERDOWN (1 << 0)
+#define UTMIP_BIAS_PDTRK_POWERUP (1 << 1)
+
+#define UTMIP_MISC_CFG0 0x824
+#define UTMIP_DPDM_OBSERVE (1 << 26)
+#define UTMIP_DPDM_OBSERVE_SEL(x) (((x) & 0xf) << 27)
+#define UTMIP_DPDM_OBSERVE_SEL_FS_J UTMIP_DPDM_OBSERVE_SEL(0xf)
+#define UTMIP_DPDM_OBSERVE_SEL_FS_K UTMIP_DPDM_OBSERVE_SEL(0xe)
+#define UTMIP_DPDM_OBSERVE_SEL_FS_SE1 UTMIP_DPDM_OBSERVE_SEL(0xd)
+#define UTMIP_DPDM_OBSERVE_SEL_FS_SE0 UTMIP_DPDM_OBSERVE_SEL(0xc)
+#define UTMIP_SUSPEND_EXIT_ON_EDGE (1 << 22)
+#define FORCE_PULLDN_DM (1 << 8)
+#define FORCE_PULLDN_DP (1 << 9)
+#define COMB_TERMS (1 << 0)
+#define ALWAYS_FREE_RUNNING_TERMS (1 << 1)
+
+#define UTMIP_SPARE_CFG0 0x834
+#define FUSE_SETUP_SEL (1 << 3)
+#define FUSE_ATERM_SEL (1 << 4)
+
+#define UTMIP_PMC_WAKEUP0 0x84c
+#define EVENT_INT_ENB (1 << 0)
+
+#define UHSIC_PMC_WAKEUP0 0xc34
+
+#define UTMIP_BIAS_STS0 0x840
+#define UTMIP_RCTRL_VAL(x) (((x) & 0xffff) << 0)
+#define UTMIP_TCTRL_VAL(x) (((x) & (0xffff << 16)) >> 16)
+
+#define UHSIC_PLL_CFG1 0xc04
+#define UHSIC_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0)
+#define UHSIC_PLLU_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 14)
+
+#define UHSIC_HSRX_CFG0 0xc08
+#define UHSIC_ELASTIC_UNDERRUN_LIMIT(x) (((x) & 0x1f) << 2)
+#define UHSIC_ELASTIC_OVERRUN_LIMIT(x) (((x) & 0x1f) << 8)
+#define UHSIC_IDLE_WAIT(x) (((x) & 0x1f) << 13)
+
+#define UHSIC_HSRX_CFG1 0xc0c
+#define UHSIC_HS_SYNC_START_DLY(x) (((x) & 0x1f) << 1)
+
+#define UHSIC_TX_CFG0 0xc10
+#define UHSIC_HS_READY_WAIT_FOR_VALID (1 << 9)
+#define UHSIC_MISC_CFG0 0xc14
+#define UHSIC_SUSPEND_EXIT_ON_EDGE (1 << 7)
+#define UHSIC_DETECT_SHORT_CONNECT (1 << 8)
+#define UHSIC_FORCE_XCVR_MODE (1 << 15)
+#define UHSIC_DISABLE_BUSRESET (1 << 20)
+#define UHSIC_MISC_CFG1 0xc18
+#define UHSIC_PLLU_STABLE_COUNT(x) (((x) & 0xfff) << 2)
+
+#define UHSIC_PADS_CFG0 0xc1c
+#define UHSIC_TX_RTUNEN 0xf000
+#define UHSIC_TX_RTUNE(x) (((x) & 0xf) << 12)
+
+#define UHSIC_PADS_CFG1 0xc20
+#define UHSIC_PD_BG (1 << 2)
+#define UHSIC_PD_TX (1 << 3)
+#define UHSIC_PD_TRK (1 << 4)
+#define UHSIC_PD_RX (1 << 5)
+#define UHSIC_PD_ZI (1 << 6)
+#define UHSIC_RX_SEL (1 << 7)
+#define UHSIC_RPD_DATA (1 << 9)
+#define UHSIC_RPD_STROBE (1 << 10)
+#define UHSIC_RPU_DATA (1 << 11)
+#define UHSIC_RPU_STROBE (1 << 12)
+
+#define UHSIC_CMD_CFG0 0xc24
+#define UHSIC_PRETEND_CONNECT_DETECT (1 << 5)
+
+#define UHSIC_STAT_CFG0 0xc28
+#define UHSIC_CONNECT_DETECT (1 << 0)
+
+#define PMC_USB_DEBOUNCE 0xec
+#define UTMIP_LINE_DEB_CNT(x) (((x) & 0xf) << 16)
+#define UHSIC_LINE_DEB_CNT(x) (((x) & 0xf) << 20)
+
+#define PMC_USB_AO 0xf0
+
+#define PMC_POWER_DOWN_MASK 0xffff
+#define HSIC_RESERVED_P0 (3 << 14)
+#define STROBE_VAL_PD_P0 (1 << 12)
+#define DATA_VAL_PD_P0 (1 << 13)
+
+#define USB_ID_PD(inst) (1 << ((4*(inst))+3))
+#define VBUS_WAKEUP_PD(inst) (1 << ((4*(inst))+2))
+#define USBON_VAL_PD(inst) (1 << ((4*(inst))+1))
+#define USBON_VAL_PD_P2 (1 << 9)
+#define USBON_VAL_PD_P1 (1 << 5)
+#define USBON_VAL_PD_P0 (1 << 1)
+#define USBOP_VAL_PD(inst) (1 << (4*(inst)))
+#define USBOP_VAL_PD_P2 (1 << 8)
+#define USBOP_VAL_PD_P1 (1 << 4)
+#define USBOP_VAL_PD_P0 (1 << 0)
+#define PMC_USB_AO_PD_P2 (0xf << 8)
+#define PMC_USB_AO_ID_PD_P0 (1 << 3)
+#define PMC_USB_AO_VBUS_WAKEUP_PD_P0 (1 << 2)
+
+#define PMC_TRIGGERS 0x1ec
+
+#define UHSIC_CLR_WALK_PTR_P0 (1 << 3)
+#define UTMIP_CLR_WALK_PTR(inst) (1 << (inst))
+#define UTMIP_CLR_WALK_PTR_P2 (1 << 2)
+#define UTMIP_CLR_WALK_PTR_P1 (1 << 1)
+#define UTMIP_CLR_WALK_PTR_P0 (1 << 0)
+#define UTMIP_CAP_CFG(inst) (1 << ((inst)+4))
+#define UTMIP_CAP_CFG_P2 (1 << 6)
+#define UTMIP_CAP_CFG_P1 (1 << 5)
+#define UTMIP_CAP_CFG_P0 (1 << 4)
+#define UTMIP_CLR_WAKE_ALARM(inst) (1 << ((inst)+12))
+#define UHSIC_CLR_WAKE_ALARM_P0 (1 << 15)
+#define UTMIP_CLR_WAKE_ALARM_P2 (1 << 14)
+
+#define PMC_PAD_CFG (0x1f4)
+
+#define PMC_UTMIP_TERM_PAD_CFG 0x1f8
+#define PMC_TCTRL_VAL(x) (((x) & 0x1f) << 5)
+#define PMC_RCTRL_VAL(x) (((x) & 0x1f) << 0)
+
+#define PMC_SLEEP_CFG 0x1fc
+
+#define UHSIC_MASTER_ENABLE (1 << 24)
+#define UHSIC_WAKE_VAL(x) (((x) & 0xf) << 28)
+#define WAKE_VAL_SD10 0x2
+#define UTMIP_TCTRL_USE_PMC(inst) (1 << ((8*(inst))+3))
+#define UTMIP_TCTRL_USE_PMC_P2 (1 << 19)
+#define UTMIP_TCTRL_USE_PMC_P1 (1 << 11)
+#define UTMIP_TCTRL_USE_PMC_P0 (1 << 3)
+#define UTMIP_RCTRL_USE_PMC(inst) (1 << ((8*(inst))+2))
+#define UTMIP_RCTRL_USE_PMC_P2 (1 << 18)
+#define UTMIP_RCTRL_USE_PMC_P1 (1 << 10)
+#define UTMIP_RCTRL_USE_PMC_P0 (1 << 2)
+#define UTMIP_FSLS_USE_PMC(inst) (1 << ((8*(inst))+1))
+#define UTMIP_FSLS_USE_PMC_P2 (1 << 17)
+#define UTMIP_FSLS_USE_PMC_P1 (1 << 9)
+#define UTMIP_FSLS_USE_PMC_P0 (1 << 1)
+#define UTMIP_MASTER_ENABLE(inst) (1 << (8*(inst)))
+#define UTMIP_MASTER_ENABLE_P2 (1 << 16)
+#define UTMIP_MASTER_ENABLE_P1 (1 << 8)
+#define UTMIP_MASTER_ENABLE_P0 (1 << 0)
+#define UHSIC_MASTER_ENABLE_P0 (1 << 24)
+#define UHSIC_WAKE_VAL_P0(x) (((x) & 0xf) << 28)
+
+#define PMC_SLEEPWALK_CFG 0x200
+
+#define UHSIC_WAKE_WALK_EN_P0 (1 << 30)
+#define UHSIC_LINEVAL_WALK_EN (1 << 31)
+#define UTMIP_LINEVAL_WALK_EN(inst) (1 << ((8*(inst))+7))
+#define UTMIP_LINEVAL_WALK_EN_P2 (1 << 23)
+#define UTMIP_LINEVAL_WALK_EN_P1 (1 << 15)
+#define UTMIP_LINEVAL_WALK_EN_P0 (1 << 7)
+#define UTMIP_WAKE_VAL(inst, x) (((x) & 0xf) << ((8*(inst))+4))
+#define UTMIP_WAKE_VAL_P2(x) (((x) & 0xf) << 20)
+#define UTMIP_WAKE_VAL_P1(x) (((x) & 0xf) << 12)
+#define UTMIP_WAKE_VAL_P0(x) (((x) & 0xf) << 4)
+#define WAKE_VAL_NONE 0xc
+#define WAKE_VAL_ANY 0xF
+#define WAKE_VAL_FSJ 0x2
+#define WAKE_VAL_FSK 0x1
+#define WAKE_VAL_SE0 0x0
+
+#define PMC_SLEEPWALK_REG(inst) (0x204 + (4*(inst)))
+#define UTMIP_USBOP_RPD_A (1 << 0)
+#define UTMIP_USBON_RPD_A (1 << 1)
+#define UTMIP_AP_A (1 << 4)
+#define UTMIP_AN_A (1 << 5)
+#define UTMIP_HIGHZ_A (1 << 6)
+#define UTMIP_USBOP_RPD_B (1 << 8)
+#define UTMIP_USBON_RPD_B (1 << 9)
+#define UTMIP_AP_B (1 << 12)
+#define UTMIP_AN_B (1 << 13)
+#define UTMIP_HIGHZ_B (1 << 14)
+#define UTMIP_USBOP_RPD_C (1 << 16)
+#define UTMIP_USBON_RPD_C (1 << 17)
+#define UTMIP_AP_C (1 << 20)
+#define UTMIP_AN_C (1 << 21)
+#define UTMIP_HIGHZ_C (1 << 22)
+#define UTMIP_USBOP_RPD_D (1 << 24)
+#define UTMIP_USBON_RPD_D (1 << 25)
+#define UTMIP_AP_D (1 << 28)
+#define UTMIP_AN_D (1 << 29)
+#define UTMIP_HIGHZ_D (1 << 30)
+
+#define PMC_SLEEPWALK_UHSIC 0x210
+
+#define UHSIC_STROBE_RPD_A (1 << 0)
+#define UHSIC_DATA_RPD_A (1 << 1)
+#define UHSIC_STROBE_RPU_A (1 << 2)
+#define UHSIC_DATA_RPU_A (1 << 3)
+#define UHSIC_STROBE_RPD_B (1 << 8)
+#define UHSIC_DATA_RPD_B (1 << 9)
+#define UHSIC_STROBE_RPU_B (1 << 10)
+#define UHSIC_DATA_RPU_B (1 << 11)
+#define UHSIC_STROBE_RPD_C (1 << 16)
+#define UHSIC_DATA_RPD_C (1 << 17)
+#define UHSIC_STROBE_RPU_C (1 << 18)
+#define UHSIC_DATA_RPU_C (1 << 19)
+#define UHSIC_STROBE_RPD_D (1 << 24)
+#define UHSIC_DATA_RPD_D (1 << 25)
+#define UHSIC_STROBE_RPU_D (1 << 26)
+#define UHSIC_DATA_RPU_D (1 << 27)
+
+#define UTMIP_UHSIC_STATUS 0x214
+
+#define UTMIP_USBOP_VAL(inst) (1 << ((2*(inst)) + 8))
+#define UTMIP_USBOP_VAL_P2 (1 << 12)
+#define UTMIP_USBOP_VAL_P1 (1 << 10)
+#define UTMIP_USBOP_VAL_P0 (1 << 8)
+#define UTMIP_USBON_VAL(inst) (1 << ((2*(inst)) + 9))
+#define UTMIP_USBON_VAL_P2 (1 << 13)
+#define UTMIP_USBON_VAL_P1 (1 << 11)
+#define UTMIP_USBON_VAL_P0 (1 << 9)
+#define UHSIC_WAKE_ALARM (1 << 19)
+#define UTMIP_WAKE_ALARM(inst) (1 << ((inst) + 16))
+#define UTMIP_WAKE_ALARM_P2 (1 << 18)
+#define UTMIP_WAKE_ALARM_P1 (1 << 17)
+#define UTMIP_WAKE_ALARM_P0 (1 << 16)
+#define UHSIC_DATA_VAL_P0 (1 << 15)
+#define UHSIC_STROBE_VAL_P0 (1 << 14)
+#define UTMIP_WALK_PTR_VAL(inst) (0x3 << ((inst)*2))
+#define UHSIC_WALK_PTR_VAL (0x3 << 6)
+#define UTMIP_WALK_PTR(inst) (1 << ((inst)*2))
+#define UTMIP_WALK_PTR_P2 (1 << 4)
+#define UTMIP_WALK_PTR_P1 (1 << 2)
+#define UTMIP_WALK_PTR_P0 (1 << 0)
+
+#define USB1_PREFETCH_ID 6
+#define USB2_PREFETCH_ID 18
+#define USB3_PREFETCH_ID 17
+
+#define PMC_UTMIP_UHSIC_FAKE 0x218
+
+#define UHSIC_STROBE_VAL (1 << 12)
+#define UHSIC_DATA_VAL (1 << 13)
+#define UHSIC_STROBE_ENB (1 << 14)
+#define UHSIC_DATA_ENB (1 << 15)
+#define USBON_VAL(inst) (1 << ((4*(inst))+1))
+#define USBON_VAL_P2 (1 << 9)
+#define USBON_VAL_P1 (1 << 5)
+#define USBON_VAL_P0 (1 << 1)
+#define USBOP_VAL(inst) (1 << (4*(inst)))
+#define USBOP_VAL_P2 (1 << 8)
+#define USBOP_VAL_P1 (1 << 4)
+#define USBOP_VAL_P0 (1 << 0)
+
+#define PMC_UTMIP_BIAS_MASTER_CNTRL 0x30c
+#define BIAS_MASTER_PROG_VAL (1 << 1)
+
+#define PMC_UTMIP_MASTER_CONFIG 0x310
+
+#define UTMIP_PWR(inst) (1 << (inst))
+#define UHSIC_PWR (1 << 3)
+
+#define FUSE_USB_CALIB_0 0x1F0
+#define XCVR_SETUP(x) (((x) & 0x7F) << 0)
+#define XCVR_SETUP_LSB_MASK 0xF
+#define XCVR_SETUP_MSB_MASK 0x70
+#define XCVR_SETUP_LSB_MAX_VAL 0xF
+
+#define APB_MISC_GP_OBSCTRL_0 0x818
+#define APB_MISC_GP_OBSDATA_0 0x81c
+
+/* ULPI GPIO */
+#define ULPI_STP TEGRA_GPIO_PY3
+#define ULPI_DIR TEGRA_GPIO_PY1
+#define ULPI_D0 TEGRA_GPIO_PO1
+#define ULPI_D1 TEGRA_GPIO_PO2
+
+/* These values (in milli second) are taken from the battery charging spec */
+#define TDP_SRC_ON_MS 100
+#define TDPSRC_CON_MS 40
+
+#ifdef DEBUG
+#define DBG(stuff...) pr_info("tegra3_usb_phy: " stuff)
+#else
+#define DBG(stuff...) do {} while (0)
+#endif
+
+#if 0
+#define PHY_DBG(stuff...) pr_info("tegra3_usb_phy: " stuff)
+#else
+#define PHY_DBG(stuff...) do {} while (0)
+#endif
+
+
+static u32 utmip_rctrl_val, utmip_tctrl_val;
+static DEFINE_SPINLOCK(utmip_pad_lock);
+static int utmip_pad_count;
+
+static struct tegra_xtal_freq utmip_freq_table[] = {
+ {
+ .freq = 12000000,
+ .enable_delay = 0x02,
+ .stable_count = 0x2F,
+ .active_delay = 0x04,
+ .xtal_freq_count = 0x76,
+ .debounce = 0x7530,
+ .pdtrk_count = 5,
+ },
+ {
+ .freq = 13000000,
+ .enable_delay = 0x02,
+ .stable_count = 0x33,
+ .active_delay = 0x05,
+ .xtal_freq_count = 0x7F,
+ .debounce = 0x7EF4,
+ .pdtrk_count = 5,
+ },
+ {
+ .freq = 19200000,
+ .enable_delay = 0x03,
+ .stable_count = 0x4B,
+ .active_delay = 0x06,
+ .xtal_freq_count = 0xBB,
+ .debounce = 0xBB80,
+ .pdtrk_count = 7,
+ },
+ {
+ .freq = 26000000,
+ .enable_delay = 0x04,
+ .stable_count = 0x66,
+ .active_delay = 0x09,
+ .xtal_freq_count = 0xFE,
+ .debounce = 0xFDE8,
+ .pdtrk_count = 9,
+ },
+};
+
+static struct tegra_xtal_freq uhsic_freq_table[] = {
+ {
+ .freq = 12000000,
+ .enable_delay = 0x02,
+ .stable_count = 0x2F,
+ .active_delay = 0x0,
+ .xtal_freq_count = 0x1CA,
+ },
+ {
+ .freq = 13000000,
+ .enable_delay = 0x02,
+ .stable_count = 0x33,
+ .active_delay = 0x0,
+ .xtal_freq_count = 0x1F0,
+ },
+ {
+ .freq = 19200000,
+ .enable_delay = 0x03,
+ .stable_count = 0x4B,
+ .active_delay = 0x0,
+ .xtal_freq_count = 0x2DD,
+ },
+ {
+ .freq = 26000000,
+ .enable_delay = 0x04,
+ .stable_count = 0x66,
+ .active_delay = 0x0,
+ .xtal_freq_count = 0x3E0,
+ },
+};
+
+static void usb_phy_fence_read(struct tegra_usb_phy *phy)
+{
+ /* Fence read for coherency of AHB master intiated writes */
+ if (phy->inst == 0)
+ readb(IO_ADDRESS(IO_PPCS_PHYS + USB1_PREFETCH_ID));
+ else if (phy->inst == 1)
+ readb(IO_ADDRESS(IO_PPCS_PHYS + USB2_PREFETCH_ID));
+ else if (phy->inst == 2)
+ readb(IO_ADDRESS(IO_PPCS_PHYS + USB3_PREFETCH_ID));
+
+ return;
+}
+
+static void utmip_setup_pmc_wake_detect(struct tegra_usb_phy *phy)
+{
+ unsigned long val, pmc_pad_cfg_val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ unsigned int inst = phy->inst;
+ void __iomem *base = phy->regs;
+ bool port_connected;
+ enum usb_phy_port_speed port_speed;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ /* check for port connect status */
+ val = readl(base + USB_PORTSC);
+ port_connected = val & USB_PORTSC_CCS;
+
+ if (!port_connected)
+ return;
+
+ port_speed = (readl(base + HOSTPC1_DEVLC) >> 25) &
+ HOSTPC1_DEVLC_PSPD_MASK;
+ /*Set PMC MASTER bits to do the following
+ * a. Take over the UTMI drivers
+ * b. set up such that it will take over resume
+ * if remote wakeup is detected
+ * Prepare PMC to take over suspend-wake detect-drive resume until USB
+ * controller ready
+ */
+
+ /* disable master enable in PMC */
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~UTMIP_MASTER_ENABLE(inst);
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ /* UTMIP_PWR_PX=1 for power savings mode */
+ val = readl(pmc_base + PMC_UTMIP_MASTER_CONFIG);
+ val |= UTMIP_PWR(inst);
+ writel(val, pmc_base + PMC_UTMIP_MASTER_CONFIG);
+
+ /* config debouncer */
+ val = readl(pmc_base + PMC_USB_DEBOUNCE);
+ val &= ~UTMIP_LINE_DEB_CNT(~0);
+ val |= UTMIP_LINE_DEB_CNT(4);
+ writel(val, pmc_base + PMC_USB_DEBOUNCE);
+
+ /* Make sure nothing is happening on the line with respect to PMC */
+ val = readl(pmc_base + PMC_UTMIP_UHSIC_FAKE);
+ val &= ~USBOP_VAL(inst);
+ val &= ~USBON_VAL(inst);
+ writel(val, pmc_base + PMC_UTMIP_UHSIC_FAKE);
+
+ /* Make sure wake value for line is none */
+ val = readl(pmc_base + PMC_SLEEPWALK_CFG);
+ val &= ~UTMIP_LINEVAL_WALK_EN(inst);
+ writel(val, pmc_base + PMC_SLEEPWALK_CFG);
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~UTMIP_WAKE_VAL(inst, ~0);
+ val |= UTMIP_WAKE_VAL(inst, WAKE_VAL_NONE);
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ /* turn off pad detectors */
+ val = readl(pmc_base + PMC_USB_AO);
+ val |= (USBOP_VAL_PD(inst) | USBON_VAL_PD(inst));
+ writel(val, pmc_base + PMC_USB_AO);
+
+ /* Remove fake values and make synchronizers work a bit */
+ val = readl(pmc_base + PMC_UTMIP_UHSIC_FAKE);
+ val &= ~USBOP_VAL(inst);
+ val &= ~USBON_VAL(inst);
+ writel(val, pmc_base + PMC_UTMIP_UHSIC_FAKE);
+
+ /* Enable which type of event can trigger a walk,
+ in this case usb_line_wake */
+ val = readl(pmc_base + PMC_SLEEPWALK_CFG);
+ val |= UTMIP_LINEVAL_WALK_EN(inst);
+ writel(val, pmc_base + PMC_SLEEPWALK_CFG);
+
+ /* Enable which type of event can trigger a walk,
+ * in this case usb_line_wake */
+ val = readl(pmc_base + PMC_SLEEPWALK_CFG);
+ val |= UTMIP_LINEVAL_WALK_EN(inst);
+ writel(val, pmc_base + PMC_SLEEPWALK_CFG);
+
+ /* Capture FS/LS pad configurations */
+ pmc_pad_cfg_val = readl(pmc_base + PMC_PAD_CFG);
+ val = readl(pmc_base + PMC_TRIGGERS);
+ val |= UTMIP_CAP_CFG(inst);
+ writel(val, pmc_base + PMC_TRIGGERS);
+ udelay(1);
+ pmc_pad_cfg_val = readl(pmc_base + PMC_PAD_CFG);
+
+ /* BIAS MASTER_ENABLE=0 */
+ val = readl(pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL);
+ val &= ~BIAS_MASTER_PROG_VAL;
+ writel(val, pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL);
+
+ /* program walk sequence, maintain a J, followed by a driven K
+ * to signal a resume once an wake event is detected */
+ val = readl(pmc_base + PMC_SLEEPWALK_REG(inst));
+ val &= ~UTMIP_AP_A;
+ val |= UTMIP_USBOP_RPD_A | UTMIP_USBON_RPD_A | UTMIP_AN_A |UTMIP_HIGHZ_A |
+ UTMIP_USBOP_RPD_B | UTMIP_USBON_RPD_B | UTMIP_AP_B | UTMIP_AN_B |
+ UTMIP_USBOP_RPD_C | UTMIP_USBON_RPD_C | UTMIP_AP_C | UTMIP_AN_C |
+ UTMIP_USBOP_RPD_D | UTMIP_USBON_RPD_D | UTMIP_AP_D | UTMIP_AN_D;
+ writel(val, pmc_base + PMC_SLEEPWALK_REG(inst));
+
+ if (port_speed == USB_PHY_PORT_SPEED_LOW) {
+ val = readl(pmc_base + PMC_SLEEPWALK_REG(inst));
+ val &= ~(UTMIP_AN_B | UTMIP_HIGHZ_B | UTMIP_AN_C |
+ UTMIP_HIGHZ_C | UTMIP_AN_D | UTMIP_HIGHZ_D);
+ writel(val, pmc_base + PMC_SLEEPWALK_REG(inst));
+ } else {
+ val = readl(pmc_base + PMC_SLEEPWALK_REG(inst));
+ val &= ~(UTMIP_AP_B | UTMIP_HIGHZ_B | UTMIP_AP_C |
+ UTMIP_HIGHZ_C | UTMIP_AP_D | UTMIP_HIGHZ_D);
+ writel(val, pmc_base + PMC_SLEEPWALK_REG(inst));
+ }
+
+ /* turn on pad detectors */
+ val = readl(pmc_base + PMC_USB_AO);
+ val &= ~(USBOP_VAL_PD(inst) | USBON_VAL_PD(inst));
+ writel(val, pmc_base + PMC_USB_AO);
+
+ /* Add small delay before usb detectors provide stable line values */
+ mdelay(1);
+
+ /* Program thermally encoded RCTRL_VAL, TCTRL_VAL into PMC space */
+ val = readl(pmc_base + PMC_UTMIP_TERM_PAD_CFG);
+ val = PMC_TCTRL_VAL(utmip_tctrl_val) | PMC_RCTRL_VAL(utmip_rctrl_val);
+ writel(val, pmc_base + PMC_UTMIP_TERM_PAD_CFG);
+
+ phy->remote_wakeup = false;
+
+ /* Turn over pad configuration to PMC for line wake events*/
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~UTMIP_WAKE_VAL(inst, ~0);
+ val |= UTMIP_WAKE_VAL(inst, WAKE_VAL_ANY);
+ val |= UTMIP_RCTRL_USE_PMC(inst) | UTMIP_TCTRL_USE_PMC(inst);
+ val |= UTMIP_MASTER_ENABLE(inst) | UTMIP_FSLS_USE_PMC(inst);
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ val = readl(base + UTMIP_PMC_WAKEUP0);
+ val |= EVENT_INT_ENB;
+ writel(val, base + UTMIP_PMC_WAKEUP0);
+ PHY_DBG("%s ENABLE_PMC inst = %d\n", __func__, inst);
+}
+
+static void utmip_phy_disable_pmc_bus_ctrl(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ unsigned int inst = phy->inst;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~UTMIP_WAKE_VAL(inst, 0xF);
+ val |= UTMIP_WAKE_VAL(inst, WAKE_VAL_NONE);
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ val = readl(pmc_base + PMC_TRIGGERS);
+ val |= UTMIP_CLR_WAKE_ALARM(inst) | UTMIP_CLR_WALK_PTR(inst);
+ writel(val, pmc_base + PMC_TRIGGERS);
+
+ val = readl(base + UTMIP_PMC_WAKEUP0);
+ val &= ~EVENT_INT_ENB;
+ writel(val, base + UTMIP_PMC_WAKEUP0);
+
+ /* Disable PMC master mode by clearing MASTER_EN */
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~(UTMIP_RCTRL_USE_PMC(inst) | UTMIP_TCTRL_USE_PMC(inst) |
+ UTMIP_FSLS_USE_PMC(inst) | UTMIP_MASTER_ENABLE(inst));
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ val = readl(pmc_base + PMC_TRIGGERS);
+ val &= ~UTMIP_CAP_CFG(inst);
+ writel(val, pmc_base + PMC_TRIGGERS);
+
+ /* turn off pad detectors */
+ val = readl(pmc_base + PMC_USB_AO);
+ val |= (USBOP_VAL_PD(inst) | USBON_VAL_PD(inst));
+ writel(val, pmc_base + PMC_USB_AO);
+
+ phy->remote_wakeup = false;
+ PHY_DBG("%s DISABLE_PMC inst = %d\n", __func__, inst);
+}
+
+bool utmi_phy_remotewake_detected(struct tegra_usb_phy *phy)
+{
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ void __iomem *base = phy->regs;
+ unsigned int inst = phy->inst;
+ u32 val;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ val = readl(base + UTMIP_PMC_WAKEUP0);
+ if (val & EVENT_INT_ENB) {
+ val = readl(pmc_base + UTMIP_UHSIC_STATUS);
+ if (UTMIP_WAKE_ALARM(inst) & val) {
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~UTMIP_WAKE_VAL(inst, 0xF);
+ val |= UTMIP_WAKE_VAL(inst, WAKE_VAL_NONE);
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ val = readl(pmc_base + PMC_TRIGGERS);
+ val |= UTMIP_CLR_WAKE_ALARM(inst) |
+ UTMIP_CLR_WALK_PTR(inst);
+ writel(val, pmc_base + PMC_TRIGGERS);
+
+ val = readl(base + UTMIP_PMC_WAKEUP0);
+ val &= ~EVENT_INT_ENB;
+ writel(val, base + UTMIP_PMC_WAKEUP0);
+ phy->remote_wakeup = true;
+ return true;
+ }
+ }
+ return false;
+}
+
+static void utmi_phy_enable_trking_data(struct tegra_usb_phy *phy)
+{
+ void __iomem *base = IO_ADDRESS(TEGRA_USB_BASE);
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ static bool init_done = false;
+ u32 val;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ /* Should be done only once after system boot */
+ if (init_done)
+ return;
+
+ clk_enable(phy->utmi_pad_clk);
+ /* Bias pad MASTER_ENABLE=1 */
+ val = readl(pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL);
+ val |= BIAS_MASTER_PROG_VAL;
+ writel(val, pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL);
+
+ /* Setting the tracking length time */
+ val = readl(base + UTMIP_BIAS_CFG1);
+ val &= ~UTMIP_BIAS_PDTRK_COUNT(~0);
+ val |= UTMIP_BIAS_PDTRK_COUNT(5);
+ writel(val, base + UTMIP_BIAS_CFG1);
+
+ /* Bias PDTRK is Shared and MUST be done from USB1 ONLY, PD_TRK=0 */
+ val = readl(base + UTMIP_BIAS_CFG1);
+ val &= ~UTMIP_BIAS_PDTRK_POWERDOWN;
+ writel(val, base + UTMIP_BIAS_CFG1);
+
+ val = readl(base + UTMIP_BIAS_CFG1);
+ val |= UTMIP_BIAS_PDTRK_POWERUP;
+ writel(val, base + UTMIP_BIAS_CFG1);
+
+ /* Wait for 25usec */
+ udelay(25);
+
+ /* Bias pad MASTER_ENABLE=0 */
+ val = readl(pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL);
+ val &= ~BIAS_MASTER_PROG_VAL;
+ writel(val, pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL);
+
+ /* Wait for 1usec */
+ udelay(1);
+
+ /* Bias pad MASTER_ENABLE=1 */
+ val = readl(pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL);
+ val |= BIAS_MASTER_PROG_VAL;
+ writel(val, pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL);
+
+ /* Read RCTRL and TCTRL from UTMIP space */
+ val = readl(base + UTMIP_BIAS_STS0);
+ utmip_rctrl_val = ffz(UTMIP_RCTRL_VAL(val));
+ utmip_tctrl_val = ffz(UTMIP_TCTRL_VAL(val));
+
+ /* PD_TRK=1 */
+ val = readl(base + UTMIP_BIAS_CFG1);
+ val |= UTMIP_BIAS_PDTRK_POWERDOWN;
+ writel(val, base + UTMIP_BIAS_CFG1);
+
+ /* Program thermally encoded RCTRL_VAL, TCTRL_VAL into PMC space */
+ val = readl(pmc_base + PMC_UTMIP_TERM_PAD_CFG);
+ val = PMC_TCTRL_VAL(utmip_tctrl_val) | PMC_RCTRL_VAL(utmip_rctrl_val);
+ writel(val, pmc_base + PMC_UTMIP_TERM_PAD_CFG);
+ clk_disable(phy->utmi_pad_clk);
+ init_done = true;
+}
+
+static void utmip_powerdown_pmc_wake_detect(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ unsigned int inst = phy->inst;
+
+ /* power down UTMIP interfaces */
+ val = readl(pmc_base + PMC_UTMIP_MASTER_CONFIG);
+ val |= UTMIP_PWR(inst);
+ writel(val, pmc_base + PMC_UTMIP_MASTER_CONFIG);
+
+ /* setup sleep walk usb controller */
+ val = UTMIP_USBOP_RPD_A | UTMIP_USBON_RPD_A | UTMIP_HIGHZ_A |
+ UTMIP_USBOP_RPD_B | UTMIP_USBON_RPD_B | UTMIP_HIGHZ_B |
+ UTMIP_USBOP_RPD_C | UTMIP_USBON_RPD_C | UTMIP_HIGHZ_C |
+ UTMIP_USBOP_RPD_D | UTMIP_USBON_RPD_D | UTMIP_HIGHZ_D;
+ writel(val, pmc_base + PMC_SLEEPWALK_REG(inst));
+
+ /* Program thermally encoded RCTRL_VAL, TCTRL_VAL into PMC space */
+ val = readl(pmc_base + PMC_UTMIP_TERM_PAD_CFG);
+ val = PMC_TCTRL_VAL(utmip_tctrl_val) | PMC_RCTRL_VAL(utmip_rctrl_val);
+ writel(val, pmc_base + PMC_UTMIP_TERM_PAD_CFG);
+
+ /* Turn over pad configuration to PMC */
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~UTMIP_WAKE_VAL(inst, ~0);
+ val |= UTMIP_WAKE_VAL(inst, WAKE_VAL_NONE) |
+ UTMIP_RCTRL_USE_PMC(inst) | UTMIP_TCTRL_USE_PMC(inst) |
+ UTMIP_FSLS_USE_PMC(inst) | UTMIP_MASTER_ENABLE(inst);
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+ PHY_DBG("%s ENABLE_PMC inst = %d\n", __func__, inst);
+}
+
+static void utmip_powerup_pmc_wake_detect(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ unsigned int inst = phy->inst;
+
+ /* Disable PMC master mode by clearing MASTER_EN */
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~(UTMIP_RCTRL_USE_PMC(inst) | UTMIP_TCTRL_USE_PMC(inst) |
+ UTMIP_FSLS_USE_PMC(inst) | UTMIP_MASTER_ENABLE(inst));
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+ mdelay(1);
+ PHY_DBG("%s DISABLE_PMC inst = %d\n", __func__, inst);
+}
+
+
+#ifdef KERNEL_WARNING
+static void usb_phy_power_down_pmc(void)
+{
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+
+ /* power down all 3 UTMIP interfaces */
+ val = readl(pmc_base + PMC_UTMIP_MASTER_CONFIG);
+ val |= UTMIP_PWR(0) | UTMIP_PWR(1) | UTMIP_PWR(2);
+ writel(val, pmc_base + PMC_UTMIP_MASTER_CONFIG);
+
+ /* turn on pad detectors */
+ writel(PMC_POWER_DOWN_MASK, pmc_base + PMC_USB_AO);
+
+ /* setup sleep walk fl all 3 usb controllers */
+ val = UTMIP_USBOP_RPD_A | UTMIP_USBON_RPD_A | UTMIP_HIGHZ_A |
+ UTMIP_USBOP_RPD_B | UTMIP_USBON_RPD_B | UTMIP_HIGHZ_B |
+ UTMIP_USBOP_RPD_C | UTMIP_USBON_RPD_C | UTMIP_HIGHZ_C |
+ UTMIP_USBOP_RPD_D | UTMIP_USBON_RPD_D | UTMIP_HIGHZ_D;
+ writel(val, pmc_base + PMC_SLEEPWALK_REG(0));
+ writel(val, pmc_base + PMC_SLEEPWALK_REG(1));
+ writel(val, pmc_base + PMC_SLEEPWALK_REG(2));
+
+ /* enable pull downs on HSIC PMC */
+ val = UHSIC_STROBE_RPD_A | UHSIC_DATA_RPD_A | UHSIC_STROBE_RPD_B |
+ UHSIC_DATA_RPD_B | UHSIC_STROBE_RPD_C | UHSIC_DATA_RPD_C |
+ UHSIC_STROBE_RPD_D | UHSIC_DATA_RPD_D;
+ writel(val, pmc_base + PMC_SLEEPWALK_UHSIC);
+
+ /* Turn over pad configuration to PMC */
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~UTMIP_WAKE_VAL(0, ~0);
+ val &= ~UTMIP_WAKE_VAL(1, ~0);
+ val &= ~UTMIP_WAKE_VAL(2, ~0);
+ val &= ~UHSIC_WAKE_VAL_P0(~0);
+ val |= UTMIP_WAKE_VAL(0, WAKE_VAL_NONE) | UHSIC_WAKE_VAL_P0(WAKE_VAL_NONE) |
+ UTMIP_WAKE_VAL(1, WAKE_VAL_NONE) | UTMIP_WAKE_VAL(2, WAKE_VAL_NONE) |
+ UTMIP_RCTRL_USE_PMC(0) | UTMIP_RCTRL_USE_PMC(1) | UTMIP_RCTRL_USE_PMC(2) |
+ UTMIP_TCTRL_USE_PMC(0) | UTMIP_TCTRL_USE_PMC(1) | UTMIP_TCTRL_USE_PMC(2) |
+ UTMIP_FSLS_USE_PMC(0) | UTMIP_FSLS_USE_PMC(1) | UTMIP_FSLS_USE_PMC(2) |
+ UTMIP_MASTER_ENABLE(0) | UTMIP_MASTER_ENABLE(1) | UTMIP_MASTER_ENABLE(2) |
+ UHSIC_MASTER_ENABLE_P0;
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+}
+#endif
+
+static int usb_phy_bringup_host_controller(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ PHY_DBG("[%d] USB_USBSTS[0x%x] USB_PORTSC[0x%x] port_speed[%d]\n", __LINE__,
+ readl(base + USB_USBSTS), readl(base + USB_PORTSC),
+ phy->port_speed);
+
+ /* Device is plugged in when system is in LP0 */
+ /* Bring up the controller from LP0*/
+ val = readl(base + USB_USBCMD);
+ val |= USB_CMD_RESET;
+ writel(val, base + USB_USBCMD);
+
+ if (usb_phy_reg_status_wait(base + USB_USBCMD,
+ USB_CMD_RESET, 0, 2500) < 0) {
+ pr_err("%s: timeout waiting for reset\n", __func__);
+ }
+
+ val = readl(base + USB_USBMODE);
+ val &= ~USB_USBMODE_MASK;
+ val |= USB_USBMODE_HOST;
+ writel(val, base + USB_USBMODE);
+ val = readl(base + HOSTPC1_DEVLC);
+ val &= ~HOSTPC1_DEVLC_PTS(~0);
+
+ if (phy->pdata->phy_intf == TEGRA_USB_PHY_INTF_HSIC)
+ val |= HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_HSIC);
+ else
+ val |= HOSTPC1_DEVLC_STS;
+ writel(val, base + HOSTPC1_DEVLC);
+
+ /* Enable Port Power */
+ val = readl(base + USB_PORTSC);
+ val |= USB_PORTSC_PP;
+ writel(val, base + USB_PORTSC);
+ udelay(10);
+
+ /* Check if the phy resume from LP0. When the phy resume from LP0
+ * USB register will be reset.to zero */
+ if (!readl(base + USB_ASYNCLISTADDR)) {
+ /* Program the field PTC based on the saved speed mode */
+ val = readl(base + USB_PORTSC);
+ val &= ~USB_PORTSC_PTC(~0);
+ if (phy->port_speed == USB_PHY_PORT_SPEED_HIGH)
+ val |= USB_PORTSC_PTC(5);
+ else if (phy->port_speed == USB_PHY_PORT_SPEED_FULL)
+ val |= USB_PORTSC_PTC(6);
+ else if (phy->port_speed == USB_PHY_PORT_SPEED_LOW)
+ val |= USB_PORTSC_PTC(7);
+ writel(val, base + USB_PORTSC);
+ udelay(10);
+
+ /* Disable test mode by setting PTC field to NORMAL_OP */
+ val = readl(base + USB_PORTSC);
+ val &= ~USB_PORTSC_PTC(~0);
+ writel(val, base + USB_PORTSC);
+ udelay(10);
+ }
+
+ /* Poll until CCS is enabled */
+ if (usb_phy_reg_status_wait(base + USB_PORTSC, USB_PORTSC_CCS,
+ USB_PORTSC_CCS, 2000)) {
+ pr_err("%s: timeout waiting for USB_PORTSC_CCS\n", __func__);
+ }
+
+ /* Poll until PE is enabled */
+ if (usb_phy_reg_status_wait(base + USB_PORTSC, USB_PORTSC_PE,
+ USB_PORTSC_PE, 2000)) {
+ pr_err("%s: timeout waiting for USB_PORTSC_PE\n", __func__);
+ }
+
+ /* Clear the PCI status, to avoid an interrupt taken upon resume */
+ val = readl(base + USB_USBSTS);
+ val |= USB_USBSTS_PCI;
+ writel(val, base + USB_USBSTS);
+
+ if (!phy->remote_wakeup) {
+ /* Put controller in suspend mode by writing 1 to SUSP bit of PORTSC */
+ val = readl(base + USB_PORTSC);
+ if ((val & USB_PORTSC_PP) && (val & USB_PORTSC_PE)) {
+ val |= USB_PORTSC_SUSP;
+ writel(val, base + USB_PORTSC);
+ /* Need a 4ms delay before the controller goes to suspend */
+ mdelay(4);
+
+ /* Wait until port suspend completes */
+ if (usb_phy_reg_status_wait(base + USB_PORTSC, USB_PORTSC_SUSP,
+ USB_PORTSC_SUSP, 1000)) {
+ pr_err("%s: timeout waiting for PORT_SUSPEND\n",
+ __func__);
+ }
+ }
+ }
+ PHY_DBG("[%d] USB_USBSTS[0x%x] USB_PORTSC[0x%x] port_speed[%d]\n", __LINE__,
+ readl(base + USB_USBSTS), readl(base + USB_PORTSC),
+ phy->port_speed);
+
+ DBG("USB_USBSTS[0x%x] USB_PORTSC[0x%x]\n",
+ readl(base + USB_USBSTS), readl(base + USB_PORTSC));
+ return 0;
+}
+
+static void usb_phy_wait_for_sof(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ val = readl(base + USB_USBSTS);
+ writel(val, base + USB_USBSTS);
+ udelay(20);
+ /* wait for two SOFs */
+ if (usb_phy_reg_status_wait(base + USB_USBSTS, USB_USBSTS_SRI,
+ USB_USBSTS_SRI, 2500))
+ pr_err("%s: timeout waiting for SOF\n", __func__);
+
+ val = readl(base + USB_USBSTS);
+ writel(val, base + USB_USBSTS);
+ if (usb_phy_reg_status_wait(base + USB_USBSTS, USB_USBSTS_SRI, 0, 2500))
+ pr_err("%s: timeout waiting for SOF\n", __func__);
+
+ if (usb_phy_reg_status_wait(base + USB_USBSTS, USB_USBSTS_SRI,
+ USB_USBSTS_SRI, 2500))
+ pr_err("%s: timeout waiting for SOF\n", __func__);
+
+ udelay(20);
+}
+
+static unsigned int utmi_phy_xcvr_setup_value(struct tegra_usb_phy *phy)
+{
+ struct tegra_utmi_config *cfg = &phy->pdata->u_cfg.utmi;
+ signed long val;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ if (cfg->xcvr_use_fuses) {
+ val = XCVR_SETUP(tegra_fuse_readl(FUSE_USB_CALIB_0));
+ if (cfg->xcvr_use_lsb) {
+ val = min((unsigned int) ((val & XCVR_SETUP_LSB_MASK)
+ + cfg->xcvr_setup_offset),
+ (unsigned int) XCVR_SETUP_LSB_MAX_VAL);
+ val |= (cfg->xcvr_setup & XCVR_SETUP_MSB_MASK);
+ } else {
+ if (cfg->xcvr_setup_offset <= UTMIP_XCVR_MAX_OFFSET)
+ val = val + cfg->xcvr_setup_offset;
+
+ if (val > UTMIP_XCVR_SETUP_MAX_VALUE) {
+ val = UTMIP_XCVR_SETUP_MAX_VALUE;
+ pr_info("%s: reset XCVR_SETUP to max value\n",
+ __func__);
+ } else if (val < UTMIP_XCVR_SETUP_MIN_VALUE) {
+ val = UTMIP_XCVR_SETUP_MIN_VALUE;
+ pr_info("%s: reset XCVR_SETUP to min value\n",
+ __func__);
+ }
+ }
+ } else {
+ val = cfg->xcvr_setup;
+ }
+
+ return (unsigned int) val;
+}
+
+static int utmi_phy_open(struct tegra_usb_phy *phy)
+{
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ unsigned long parent_rate, val;
+ int i;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ phy->utmi_pad_clk = clk_get_sys("utmip-pad", NULL);
+ if (IS_ERR(phy->utmi_pad_clk)) {
+ pr_err("%s: can't get utmip pad clock\n", __func__);
+ return PTR_ERR(phy->utmi_pad_clk);
+ }
+
+ phy->utmi_xcvr_setup = utmi_phy_xcvr_setup_value(phy);
+
+ parent_rate = clk_get_rate(clk_get_parent(phy->pllu_clk));
+ for (i = 0; i < ARRAY_SIZE(utmip_freq_table); i++) {
+ if (utmip_freq_table[i].freq == parent_rate) {
+ phy->freq = &utmip_freq_table[i];
+ break;
+ }
+ }
+ if (!phy->freq) {
+ pr_err("invalid pll_u parent rate %ld\n", parent_rate);
+ return -EINVAL;
+ }
+
+ /* Power-up the VBUS detector for UTMIP PHY */
+ val = readl(pmc_base + PMC_USB_AO);
+ val &= ~(PMC_USB_AO_VBUS_WAKEUP_PD_P0 | PMC_USB_AO_ID_PD_P0);
+ writel((val | PMC_USB_AO_PD_P2), (pmc_base + PMC_USB_AO));
+
+ utmip_powerup_pmc_wake_detect(phy);
+
+ return 0;
+}
+
+static void utmi_phy_close(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s inst:[%d]\n", __func__, phy->inst);
+
+ /* Disable PHY clock valid interrupts while going into suspend*/
+ if (phy->pdata->u_data.host.hot_plug) {
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~USB_PHY_CLK_VALID_INT_ENB;
+ writel(val, base + USB_SUSP_CTRL);
+ }
+
+ clk_put(phy->utmi_pad_clk);
+}
+
+static int utmi_phy_pad_power_on(struct tegra_usb_phy *phy)
+{
+ unsigned long val, flags;
+ void __iomem *pad_base = IO_ADDRESS(TEGRA_USB_BASE);
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ clk_enable(phy->utmi_pad_clk);
+
+ spin_lock_irqsave(&utmip_pad_lock, flags);
+ utmip_pad_count++;
+
+ val = readl(pad_base + UTMIP_BIAS_CFG0);
+ val &= ~(UTMIP_OTGPD | UTMIP_BIASPD);
+ val |= UTMIP_HSSQUELCH_LEVEL(0x2) | UTMIP_HSDISCON_LEVEL(0x1) |
+ UTMIP_HSDISCON_LEVEL_MSB;
+ writel(val, pad_base + UTMIP_BIAS_CFG0);
+
+ spin_unlock_irqrestore(&utmip_pad_lock, flags);
+
+ clk_disable(phy->utmi_pad_clk);
+
+ return 0;
+}
+
+static int utmi_phy_pad_power_off(struct tegra_usb_phy *phy)
+{
+ unsigned long val, flags;
+ void __iomem *pad_base = IO_ADDRESS(TEGRA_USB_BASE);
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ clk_enable(phy->utmi_pad_clk);
+ spin_lock_irqsave(&utmip_pad_lock, flags);
+
+ if (!utmip_pad_count) {
+ pr_err("%s: utmip pad already powered off\n", __func__);
+ goto out;
+ }
+ if (--utmip_pad_count == 0) {
+ val = readl(pad_base + UTMIP_BIAS_CFG0);
+ val |= UTMIP_OTGPD | UTMIP_BIASPD;
+ val &= ~(UTMIP_HSSQUELCH_LEVEL(~0) | UTMIP_HSDISCON_LEVEL(~0) |
+ UTMIP_HSDISCON_LEVEL_MSB);
+ writel(val, pad_base + UTMIP_BIAS_CFG0);
+ }
+out:
+ spin_unlock_irqrestore(&utmip_pad_lock, flags);
+ clk_disable(phy->utmi_pad_clk);
+
+ return 0;
+}
+
+static int utmi_phy_irq(struct tegra_usb_phy *phy)
+{
+ void __iomem *base = phy->regs;
+ unsigned long val = 0;
+
+ if (phy->phy_clk_on) {
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ DBG("USB_USBSTS[0x%x] USB_PORTSC[0x%x]\n",
+ readl(base + USB_USBSTS), readl(base + USB_PORTSC));
+ DBG("USB_USBMODE[0x%x] USB_USBCMD[0x%x]\n",
+ readl(base + USB_USBMODE), readl(base + USB_USBCMD));
+ }
+
+ usb_phy_fence_read(phy);
+ /* check if there is any remote wake event */
+ if (utmi_phy_remotewake_detected(phy))
+ pr_info("%s: utmip remote wake detected\n", __func__);
+
+ if (phy->pdata->u_data.host.hot_plug) {
+ val = readl(base + USB_SUSP_CTRL);
+ if ((val & USB_PHY_CLK_VALID_INT_STS)) {
+ val &= ~USB_PHY_CLK_VALID_INT_ENB |
+ USB_PHY_CLK_VALID_INT_STS;
+ writel(val , (base + USB_SUSP_CTRL));
+ pr_info("%s: usb device plugged-in\n", __func__);
+ val = readl(base + USB_USBSTS);
+ if (!(val & USB_USBSTS_PCI))
+ return IRQ_NONE;
+ val = readl(base + USB_PORTSC);
+ val &= ~(USB_PORTSC_WKCN | USB_PORTSC_RWC_BITS);
+ writel(val , (base + USB_PORTSC));
+ } else if (!phy->phy_clk_on) {
+ return IRQ_NONE;
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void utmi_phy_enable_obs_bus(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ /* (2LS WAR)is not required for LS and FS devices and is only for HS */
+ if ((phy->port_speed == USB_PHY_PORT_SPEED_LOW) ||
+ (phy->port_speed == USB_PHY_PORT_SPEED_FULL)) {
+ /* do not enable the OBS bus */
+ val = readl(base + UTMIP_MISC_CFG0);
+ val &= ~(UTMIP_DPDM_OBSERVE_SEL(~0));
+ writel(val, base + UTMIP_MISC_CFG0);
+ DBG("%s(%d) Disable OBS bus\n", __func__, __LINE__);
+ return;
+ }
+ /* Force DP/DM pulldown active for Host mode */
+ val = readl(base + UTMIP_MISC_CFG0);
+ val |= FORCE_PULLDN_DM | FORCE_PULLDN_DP |
+ COMB_TERMS | ALWAYS_FREE_RUNNING_TERMS;
+ writel(val, base + UTMIP_MISC_CFG0);
+ val = readl(base + UTMIP_MISC_CFG0);
+ val &= ~UTMIP_DPDM_OBSERVE_SEL(~0);
+ if (phy->port_speed == USB_PHY_PORT_SPEED_LOW)
+ val |= UTMIP_DPDM_OBSERVE_SEL_FS_J;
+ else
+ val |= UTMIP_DPDM_OBSERVE_SEL_FS_K;
+ writel(val, base + UTMIP_MISC_CFG0);
+ udelay(1);
+
+ val = readl(base + UTMIP_MISC_CFG0);
+ val |= UTMIP_DPDM_OBSERVE;
+ writel(val, base + UTMIP_MISC_CFG0);
+ udelay(10);
+ DBG("%s(%d) Enable OBS bus\n", __func__, __LINE__);
+ PHY_DBG("ENABLE_OBS_BUS\n");
+}
+
+static int utmi_phy_disable_obs_bus(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+ unsigned long flags;
+
+ /* check if OBS bus is already enabled */
+ val = readl(base + UTMIP_MISC_CFG0);
+ if (val & UTMIP_DPDM_OBSERVE) {
+ PHY_DBG("DISABLE_OBS_BUS\n");
+
+ /* disable ALL interrupts on current CPU */
+ local_irq_save(flags);
+
+ /* Change the UTMIP OBS bus to drive SE0 */
+ val = readl(base + UTMIP_MISC_CFG0);
+ val &= ~UTMIP_DPDM_OBSERVE_SEL(~0);
+ val |= UTMIP_DPDM_OBSERVE_SEL_FS_SE0;
+ writel(val, base + UTMIP_MISC_CFG0);
+
+ /* Wait for 3us(2 LS bit times) */
+ udelay(3);
+
+ /* Release UTMIP OBS bus */
+ val = readl(base + UTMIP_MISC_CFG0);
+ val &= ~UTMIP_DPDM_OBSERVE;
+ writel(val, base + UTMIP_MISC_CFG0);
+
+ /* Release DP/DM pulldown for Host mode */
+ val = readl(base + UTMIP_MISC_CFG0);
+ val &= ~(FORCE_PULLDN_DM | FORCE_PULLDN_DP |
+ COMB_TERMS | ALWAYS_FREE_RUNNING_TERMS);
+ writel(val, base + UTMIP_MISC_CFG0);
+
+ val = readl(base + USB_USBCMD);
+ val |= USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+
+ /* restore ALL interrupts on current CPU */
+ local_irq_restore(flags);
+
+ if (usb_phy_reg_status_wait(base + USB_USBCMD, USB_USBCMD_RS,
+ USB_USBCMD_RS, 2000)) {
+ pr_err("%s: timeout waiting for USB_USBCMD_RS\n", __func__);
+ return -ETIMEDOUT;
+ }
+ }
+ return 0;
+}
+
+static int utmi_phy_post_resume(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ unsigned int inst = phy->inst;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ /* if PMC is not disabled by now then disable it */
+ if (val & UTMIP_MASTER_ENABLE(inst)) {
+ utmip_phy_disable_pmc_bus_ctrl(phy);
+ }
+
+ utmi_phy_disable_obs_bus(phy);
+
+ return 0;
+}
+
+static int utmi_phy_pre_resume(struct tegra_usb_phy *phy, bool remote_wakeup)
+{
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ void __iomem *base = phy->regs;
+ unsigned int inst = phy->inst;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ phy->port_speed = (readl(base + HOSTPC1_DEVLC) >> 25) &
+ HOSTPC1_DEVLC_PSPD_MASK;
+
+ if (phy->port_speed == USB_PHY_PORT_SPEED_HIGH) {
+ /* Disable interrupts */
+ writel(0, base + USB_USBINTR);
+ /* Clear the run bit to stop SOFs - 2LS WAR */
+ val = readl(base + USB_USBCMD);
+ val &= ~USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+ if (usb_phy_reg_status_wait(base + USB_USBSTS, USB_USBSTS_HCH,
+ USB_USBSTS_HCH, 2000)) {
+ pr_err("%s: timeout waiting for USB_USBSTS_HCH\n", __func__);
+ }
+ }
+
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ if (val & UTMIP_MASTER_ENABLE(inst)) {
+ if (!remote_wakeup)
+ utmip_phy_disable_pmc_bus_ctrl(phy);
+ } else {
+ utmi_phy_enable_obs_bus(phy);
+ }
+
+ return 0;
+}
+
+static int utmi_phy_power_off(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ PHY_DBG("%s(%d) inst:[%d] BEGIN\n", __func__, __LINE__, phy->inst);
+ if (!phy->phy_clk_on) {
+ PHY_DBG("%s(%d) inst:[%d] phy clk is already off\n",
+ __func__, __LINE__, phy->inst);
+ return 0;
+ }
+
+ if (phy->pdata->op_mode == TEGRA_USB_OPMODE_DEVICE) {
+ utmip_powerdown_pmc_wake_detect(phy);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~USB_WAKEUP_DEBOUNCE_COUNT(~0);
+ val |= USB_WAKE_ON_CNNT_EN_DEV | USB_WAKEUP_DEBOUNCE_COUNT(5);
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + UTMIP_BAT_CHRG_CFG0);
+ val |= UTMIP_PD_CHRG;
+ writel(val, base + UTMIP_BAT_CHRG_CFG0);
+ } else {
+ phy->port_speed = (readl(base + HOSTPC1_DEVLC) >> 25) &
+ HOSTPC1_DEVLC_PSPD_MASK;
+
+ /* Disable interrupts */
+ writel(0, base + USB_USBINTR);
+
+ /* Clear the run bit to stop SOFs - 2LS WAR */
+ val = readl(base + USB_USBCMD);
+ val &= ~USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+
+ if (usb_phy_reg_status_wait(base + USB_USBSTS, USB_USBSTS_HCH,
+ USB_USBSTS_HCH, 2000)) {
+ pr_err("%s: timeout waiting for USB_USBSTS_HCH\n", __func__);
+ }
+ utmip_setup_pmc_wake_detect(phy);
+ }
+
+ if (!phy->pdata->u_data.host.hot_plug) {
+ val = readl(base + UTMIP_XCVR_CFG0);
+ val |= (UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN |
+ UTMIP_FORCE_PDZI_POWERDOWN);
+ writel(val, base + UTMIP_XCVR_CFG0);
+ }
+
+ val = readl(base + UTMIP_XCVR_CFG1);
+ val |= UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN |
+ UTMIP_FORCE_PDDR_POWERDOWN;
+ writel(val, base + UTMIP_XCVR_CFG1);
+
+ val = readl(base + UTMIP_BIAS_CFG1);
+ val |= UTMIP_BIAS_PDTRK_COUNT(0x5);
+ writel(val, base + UTMIP_BIAS_CFG1);
+
+ utmi_phy_pad_power_off(phy);
+
+ if (phy->pdata->u_data.host.hot_plug) {
+ bool enable_hotplug = true;
+ /* if it is OTG port then make sure to enable hot-plug feature
+ only if host adaptor is connected, i.e id is low */
+ if (phy->pdata->port_otg) {
+ val = readl(base + USB_PHY_VBUS_WAKEUP_ID);
+ enable_hotplug = (val & USB_ID_STATUS) ? false : true;
+ }
+ if (enable_hotplug) {
+ val = readl(base + USB_PORTSC);
+ val |= USB_PORTSC_WKCN;
+ writel(val, base + USB_PORTSC);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= USB_PHY_CLK_VALID_INT_ENB;
+ writel(val, base + USB_SUSP_CTRL);
+ } else {
+ /* Disable PHY clock valid interrupts while going into suspend*/
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~USB_PHY_CLK_VALID_INT_ENB;
+ writel(val, base + USB_SUSP_CTRL);
+ }
+ }
+
+ val = readl(base + HOSTPC1_DEVLC);
+ val |= HOSTPC1_DEVLC_PHCD;
+ writel(val, base + HOSTPC1_DEVLC);
+
+ if (!phy->pdata->u_data.host.hot_plug) {
+ val = readl(base + USB_SUSP_CTRL);
+ val |= UTMIP_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+ }
+
+ phy->phy_clk_on = false;
+ phy->hw_accessible = false;
+
+ PHY_DBG("%s(%d) inst:[%d] END\n", __func__, __LINE__, phy->inst);
+
+ return 0;
+}
+
+
+static int utmi_phy_power_on(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+ struct tegra_utmi_config *config = &phy->pdata->u_cfg.utmi;
+
+ PHY_DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (phy->phy_clk_on) {
+ PHY_DBG("%s(%d) inst:[%d] phy clk is already On\n",
+ __func__, __LINE__, phy->inst);
+ return 0;
+ }
+ val = readl(base + USB_SUSP_CTRL);
+ val |= UTMIP_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + UTMIP_TX_CFG0);
+ val |= UTMIP_FS_PREABMLE_J;
+ writel(val, base + UTMIP_TX_CFG0);
+
+ val = readl(base + UTMIP_HSRX_CFG0);
+ val &= ~(UTMIP_IDLE_WAIT(~0) | UTMIP_ELASTIC_LIMIT(~0));
+ val |= UTMIP_IDLE_WAIT(config->idle_wait_delay);
+ val |= UTMIP_ELASTIC_LIMIT(config->elastic_limit);
+ writel(val, base + UTMIP_HSRX_CFG0);
+
+ val = readl(base + UTMIP_HSRX_CFG1);
+ val &= ~UTMIP_HS_SYNC_START_DLY(~0);
+ val |= UTMIP_HS_SYNC_START_DLY(config->hssync_start_delay);
+ writel(val, base + UTMIP_HSRX_CFG1);
+
+ val = readl(base + UTMIP_DEBOUNCE_CFG0);
+ val &= ~UTMIP_BIAS_DEBOUNCE_A(~0);
+ val |= UTMIP_BIAS_DEBOUNCE_A(phy->freq->debounce);
+ writel(val, base + UTMIP_DEBOUNCE_CFG0);
+
+ val = readl(base + UTMIP_MISC_CFG0);
+ val &= ~UTMIP_SUSPEND_EXIT_ON_EDGE;
+ writel(val, base + UTMIP_MISC_CFG0);
+
+ if (phy->pdata->op_mode == TEGRA_USB_OPMODE_DEVICE) {
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~(USB_WAKE_ON_CNNT_EN_DEV | USB_WAKE_ON_DISCON_EN_DEV);
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + UTMIP_BAT_CHRG_CFG0);
+ val &= ~UTMIP_PD_CHRG;
+ writel(val, base + UTMIP_BAT_CHRG_CFG0);
+ } else {
+ val = readl(base + UTMIP_BAT_CHRG_CFG0);
+ val |= UTMIP_PD_CHRG;
+ writel(val, base + UTMIP_BAT_CHRG_CFG0);
+ }
+
+ utmi_phy_pad_power_on(phy);
+
+ val = readl(base + UTMIP_XCVR_CFG0);
+ val &= ~(UTMIP_XCVR_LSBIAS_SEL | UTMIP_FORCE_PD_POWERDOWN |
+ UTMIP_FORCE_PD2_POWERDOWN | UTMIP_FORCE_PDZI_POWERDOWN |
+ UTMIP_XCVR_SETUP(~0) | UTMIP_XCVR_LSFSLEW(~0) |
+ UTMIP_XCVR_LSRSLEW(~0) | UTMIP_XCVR_HSSLEW_MSB(~0));
+ val |= UTMIP_XCVR_SETUP(phy->utmi_xcvr_setup);
+ val |= UTMIP_XCVR_SETUP_MSB(XCVR_SETUP_MSB_CALIB(phy->utmi_xcvr_setup));
+ val |= UTMIP_XCVR_LSFSLEW(config->xcvr_lsfslew);
+ val |= UTMIP_XCVR_LSRSLEW(config->xcvr_lsrslew);
+ if (!config->xcvr_use_lsb)
+ val |= UTMIP_XCVR_HSSLEW_MSB(0x8);
+ writel(val, base + UTMIP_XCVR_CFG0);
+
+ val = readl(base + UTMIP_XCVR_CFG1);
+ val &= ~(UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN |
+ UTMIP_FORCE_PDDR_POWERDOWN | UTMIP_XCVR_TERM_RANGE_ADJ(~0));
+ val |= UTMIP_XCVR_TERM_RANGE_ADJ(config->term_range_adj);
+ writel(val, base + UTMIP_XCVR_CFG1);
+
+ val = readl(base + UTMIP_BIAS_CFG1);
+ val &= ~UTMIP_BIAS_PDTRK_COUNT(~0);
+ val |= UTMIP_BIAS_PDTRK_COUNT(phy->freq->pdtrk_count);
+ writel(val, base + UTMIP_BIAS_CFG1);
+
+ val = readl(base + UTMIP_SPARE_CFG0);
+ val &= ~FUSE_SETUP_SEL;
+ val |= FUSE_ATERM_SEL;
+ writel(val, base + UTMIP_SPARE_CFG0);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= UTMIP_PHY_ENABLE;
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~UTMIP_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + HOSTPC1_DEVLC);
+ val &= ~HOSTPC1_DEVLC_PHCD;
+ writel(val, base + HOSTPC1_DEVLC);
+
+ if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL,
+ USB_PHY_CLK_VALID, USB_PHY_CLK_VALID, 2500))
+ pr_warn("%s: timeout waiting for phy to stabilize\n", __func__);
+
+ utmi_phy_enable_trking_data(phy);
+
+ if (phy->inst == 2)
+ writel(0, base + ICUSB_CTRL);
+
+ val = readl(base + USB_USBMODE);
+ val &= ~USB_USBMODE_MASK;
+ if (phy->pdata->op_mode == TEGRA_USB_OPMODE_HOST)
+ val |= USB_USBMODE_HOST;
+ else
+ val |= USB_USBMODE_DEVICE;
+ writel(val, base + USB_USBMODE);
+
+ val = readl(base + HOSTPC1_DEVLC);
+ val &= ~HOSTPC1_DEVLC_PTS(~0);
+ val |= HOSTPC1_DEVLC_STS;
+ writel(val, base + HOSTPC1_DEVLC);
+
+ if (phy->pdata->op_mode == TEGRA_USB_OPMODE_DEVICE)
+ utmip_powerup_pmc_wake_detect(phy);
+ phy->phy_clk_on = true;
+ phy->hw_accessible = true;
+ PHY_DBG("%s(%d) End inst:[%d]\n", __func__, __LINE__, phy->inst);
+ return 0;
+}
+
+static void utmi_phy_restore_start(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ int inst = phy->inst;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ val = readl(pmc_base + UTMIP_UHSIC_STATUS);
+ /* Check whether we wake up from the remote resume.
+ For lp1 case, pmc is not responsible for waking the
+ system, it's the flow controller and hence
+ UTMIP_WALK_PTR_VAL(inst) will return 0.
+ Also, for lp1 case phy->remote_wakeup will already be set
+ to true by utmi_phy_irq() when the remote wakeup happens.
+ Hence change the logic in the else part to enter only
+ if phy->remote_wakeup is not set to true by the
+ utmi_phy_irq(). */
+ if (UTMIP_WALK_PTR_VAL(inst) & val) {
+ phy->remote_wakeup = true;
+ } else if(!phy->remote_wakeup) {
+ if (!((UTMIP_USBON_VAL(phy->inst) |
+ UTMIP_USBOP_VAL(phy->inst)) & val)) {
+ utmip_phy_disable_pmc_bus_ctrl(phy);
+ }
+ }
+ utmi_phy_enable_obs_bus(phy);
+}
+
+static void utmi_phy_restore_end(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+ int wait_time_us = 25000; /* FPR should be set by this time */
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ /* check whether we wake up from the remote resume */
+ if (phy->remote_wakeup) {
+ /* wait until SUSPEND and RESUME bit is cleared on remote resume */
+ do {
+ val = readl(base + USB_PORTSC);
+ udelay(1);
+ if (wait_time_us == 0) {
+ PHY_DBG("%s PMC REMOTE WAKEUP FPR timeout val = 0x%x instance = %d\n", __func__, val, phy->inst);
+ utmip_phy_disable_pmc_bus_ctrl(phy);
+ utmi_phy_post_resume(phy);
+ return;
+ }
+ wait_time_us--;
+ } while (val & (USB_PORTSC_RESUME | USB_PORTSC_SUSP));
+
+ /* wait for 25 ms to port resume complete */
+ msleep(25);
+ /* disable PMC master control */
+ utmip_phy_disable_pmc_bus_ctrl(phy);
+
+ /* Clear PCI and SRI bits to avoid an interrupt upon resume */
+ val = readl(base + USB_USBSTS);
+ writel(val, base + USB_USBSTS);
+ /* wait to avoid SOF if there is any */
+ if (usb_phy_reg_status_wait(base + USB_USBSTS,
+ USB_USBSTS_SRI, USB_USBSTS_SRI, 2500) < 0) {
+ pr_err("%s: timeout waiting for SOF\n", __func__);
+ }
+ utmi_phy_post_resume(phy);
+ }
+}
+
+static int utmi_phy_resume(struct tegra_usb_phy *phy)
+{
+ int status = 0;
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (phy->pdata->op_mode == TEGRA_USB_OPMODE_HOST) {
+ if (phy->port_speed < USB_PHY_PORT_SPEED_UNKNOWN) {
+ utmi_phy_restore_start(phy);
+ usb_phy_bringup_host_controller(phy);
+ utmi_phy_restore_end(phy);
+ } else {
+ /* device is plugged in when system is in LP0 */
+ /* bring up the controller from LP0*/
+ val = readl(base + USB_USBCMD);
+ val |= USB_CMD_RESET;
+ writel(val, base + USB_USBCMD);
+
+ if (usb_phy_reg_status_wait(base + USB_USBCMD,
+ USB_CMD_RESET, 0, 2500) < 0) {
+ pr_err("%s: timeout waiting for reset\n", __func__);
+ }
+
+ val = readl(base + USB_USBMODE);
+ val &= ~USB_USBMODE_MASK;
+ val |= USB_USBMODE_HOST;
+ writel(val, base + USB_USBMODE);
+
+ val = readl(base + HOSTPC1_DEVLC);
+ val &= ~HOSTPC1_DEVLC_PTS(~0);
+ val |= HOSTPC1_DEVLC_STS;
+ writel(val, base + HOSTPC1_DEVLC);
+
+ writel(USB_USBCMD_RS, base + USB_USBCMD);
+
+ if (usb_phy_reg_status_wait(base + USB_USBCMD,
+ USB_USBCMD_RS, USB_USBCMD_RS, 2500) < 0) {
+ pr_err("%s: timeout waiting for run bit\n", __func__);
+ }
+
+ /* Enable Port Power */
+ val = readl(base + USB_PORTSC);
+ val |= USB_PORTSC_PP;
+ writel(val, base + USB_PORTSC);
+ udelay(10);
+
+ DBG("USB_USBSTS[0x%x] USB_PORTSC[0x%x]\n",
+ readl(base + USB_USBSTS), readl(base + USB_PORTSC));
+ }
+ }
+
+ return status;
+}
+
+bool utmi_phy_charger_detect(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+ bool status;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (phy->pdata->op_mode != TEGRA_USB_OPMODE_DEVICE) {
+ /* Charger detection is not there for ULPI
+ * return Charger not available */
+ return false;
+ }
+
+ /* Enable charger detection logic */
+ val = readl(base + UTMIP_BAT_CHRG_CFG0);
+ val |= UTMIP_OP_SRC_EN | UTMIP_ON_SINK_EN;
+ writel(val, base + UTMIP_BAT_CHRG_CFG0);
+
+ /* Source should be on for 100 ms as per USB charging spec */
+ msleep(TDP_SRC_ON_MS);
+
+ val = readl(base + USB_PHY_VBUS_WAKEUP_ID);
+ /* If charger is not connected disable the interrupt */
+ val &= ~VDAT_DET_INT_EN;
+ val |= VDAT_DET_CHG_DET;
+ writel(val, base + USB_PHY_VBUS_WAKEUP_ID);
+
+ val = readl(base + USB_PHY_VBUS_WAKEUP_ID);
+ if (val & VDAT_DET_STS)
+ status = true;
+ else
+ status = false;
+
+ /* Disable charger detection logic */
+ val = readl(base + UTMIP_BAT_CHRG_CFG0);
+ val &= ~(UTMIP_OP_SRC_EN | UTMIP_ON_SINK_EN);
+ writel(val, base + UTMIP_BAT_CHRG_CFG0);
+
+ /* Delay of 40 ms before we pull the D+ as per battery charger spec */
+ msleep(TDPSRC_CON_MS);
+
+ return status;
+}
+
+static void uhsic_powerup_pmc_wake_detect(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+
+ /* turn on pad detectors for HSIC*/
+ val = readl(pmc_base + PMC_USB_AO);
+ val &= ~(HSIC_RESERVED_P0 | STROBE_VAL_PD_P0 | DATA_VAL_PD_P0);
+ writel(val, pmc_base + PMC_USB_AO);
+
+ /* Disable PMC master mode by clearing MASTER_EN */
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~(UHSIC_MASTER_ENABLE_P0);
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+ mdelay(1);
+}
+
+static void uhsic_setup_pmc_wake_detect(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ void __iomem *base = phy->regs;
+ bool port_connected;
+
+ DBG("%s:%d\n", __func__, __LINE__);
+
+ /* check for port connect status */
+ val = readl(base + USB_PORTSC);
+ port_connected = val & USB_PORTSC_CCS;
+
+ if (!port_connected)
+ return;
+
+ /*Set PMC MASTER bits to do the following
+ * a. Take over the hsic drivers
+ * b. set up such that it will take over resume
+ * if remote wakeup is detected
+ * Prepare PMC to take over suspend-wake detect-drive resume until USB
+ * controller ready
+ */
+
+ /* disable master enable in PMC */
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~UHSIC_MASTER_ENABLE_P0;
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ /* UTMIP_PWR_PX=1 for power savings mode */
+ val = readl(pmc_base + PMC_UTMIP_MASTER_CONFIG);
+ val |= UHSIC_PWR;
+ writel(val, pmc_base + PMC_UTMIP_MASTER_CONFIG);
+
+
+ /* Enable which type of event can trigger a walk,
+ * in this case usb_line_wake */
+ val = readl(pmc_base + PMC_SLEEPWALK_CFG);
+ val |= UHSIC_LINEVAL_WALK_EN;
+ writel(val, pmc_base + PMC_SLEEPWALK_CFG);
+
+ /* program walk sequence, maintain a J, followed by a driven K
+ * to signal a resume once an wake event is detected */
+
+ val = readl(pmc_base + PMC_SLEEPWALK_UHSIC);
+
+ val &= ~UHSIC_DATA_RPU_A;
+ val |= UHSIC_DATA_RPD_A;
+ val &= ~UHSIC_STROBE_RPD_A;
+ val |= UHSIC_STROBE_RPU_A;
+ writel(val, pmc_base + PMC_SLEEPWALK_UHSIC);
+
+ val &= ~UHSIC_DATA_RPD_B;
+ val |= UHSIC_DATA_RPU_B;
+ val &= ~UHSIC_STROBE_RPU_B;
+ val |= UHSIC_STROBE_RPD_B;
+ writel(val, pmc_base + PMC_SLEEPWALK_UHSIC);
+
+ val &= ~UHSIC_DATA_RPD_C;
+ val |= UHSIC_DATA_RPU_C;
+ val &= ~UHSIC_STROBE_RPU_C;
+ val |= UHSIC_STROBE_RPD_C;
+ writel(val, pmc_base + PMC_SLEEPWALK_UHSIC);
+
+ val &= ~UHSIC_DATA_RPD_D;
+ val |= UHSIC_DATA_RPU_D;
+ val &= ~UHSIC_STROBE_RPU_D;
+ val |= UHSIC_STROBE_RPD_D;
+ writel(val, pmc_base + PMC_SLEEPWALK_UHSIC);
+
+ /* turn on pad detectors */
+ val = readl(pmc_base + PMC_USB_AO);
+ val &= ~(STROBE_VAL_PD_P0 | DATA_VAL_PD_P0);
+ writel(val, pmc_base + PMC_USB_AO);
+ /* Add small delay before usb detectors provide stable line values */
+ udelay(1);
+
+ phy->remote_wakeup = false;
+
+ /* Turn over pad configuration to PMC for line wake events*/
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~UHSIC_WAKE_VAL(~0);
+ val |= UHSIC_WAKE_VAL(WAKE_VAL_SD10);
+ val |= UHSIC_MASTER_ENABLE;
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ val = readl(base + UHSIC_PMC_WAKEUP0);
+ val |= EVENT_INT_ENB;
+ writel(val, base + UHSIC_PMC_WAKEUP0);
+
+ DBG("%s:PMC enabled for HSIC remote wakeup\n", __func__);
+}
+
+static void uhsic_phy_disable_pmc_bus_ctrl(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ void __iomem *base = phy->regs;
+
+ DBG("%s (%d)\n", __func__, __LINE__);
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~UHSIC_WAKE_VAL(0x0);
+ val |= UHSIC_WAKE_VAL(WAKE_VAL_NONE);
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ val = readl(pmc_base + PMC_TRIGGERS);
+ val |= UHSIC_CLR_WAKE_ALARM_P0 | UHSIC_CLR_WALK_PTR_P0;
+ writel(val, pmc_base + PMC_TRIGGERS);
+
+ val = readl(base + UHSIC_PMC_WAKEUP0);
+ val &= ~EVENT_INT_ENB;
+ writel(val, base + UHSIC_PMC_WAKEUP0);
+
+ /* Disable PMC master mode by clearing MASTER_EN */
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~(UHSIC_MASTER_ENABLE);
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ /* turn off pad detectors */
+ val = readl(pmc_base + PMC_USB_AO);
+ val |= (STROBE_VAL_PD_P0 | DATA_VAL_PD_P0);
+ writel(val, pmc_base + PMC_USB_AO);
+
+ phy->remote_wakeup = false;
+}
+
+static bool uhsic_phy_remotewake_detected(struct tegra_usb_phy *phy)
+{
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ void __iomem *base = phy->regs;
+ u32 val;
+
+ val = readl(base + UHSIC_PMC_WAKEUP0);
+ if (val & EVENT_INT_ENB) {
+ val = readl(pmc_base + UTMIP_UHSIC_STATUS);
+ if (UHSIC_WAKE_ALARM & val) {
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~UHSIC_WAKE_VAL(0x0);
+ val |= UHSIC_WAKE_VAL(WAKE_VAL_NONE);
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ val = readl(pmc_base + PMC_TRIGGERS);
+ val |= UHSIC_CLR_WAKE_ALARM_P0 | UHSIC_CLR_WALK_PTR_P0;
+ writel(val, pmc_base + PMC_TRIGGERS);
+
+ val = readl(base + UHSIC_PMC_WAKEUP0);
+ val &= ~EVENT_INT_ENB;
+ writel(val, base + UHSIC_PMC_WAKEUP0);
+ phy->remote_wakeup = true;
+ DBG("%s:PMC remote wakeup detected for HSIC\n", __func__);
+ return true;
+ }
+ }
+ return false;
+}
+
+static int uhsic_phy_pre_resume(struct tegra_usb_phy *phy, bool remote_wakeup)
+{
+ DBG("%s(%d)\n", __func__, __LINE__);
+
+ if (!remote_wakeup)
+ usb_phy_wait_for_sof(phy);
+
+ return 0;
+}
+
+static int uhsic_phy_post_resume(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ val = readl(base + USB_TXFILLTUNING);
+ if ((val & USB_FIFO_TXFILL_MASK) != USB_FIFO_TXFILL_THRES(0x10)) {
+ val = USB_FIFO_TXFILL_THRES(0x10);
+ writel(val, base + USB_TXFILLTUNING);
+ }
+
+ return 0;
+}
+
+static void uhsic_phy_restore_start(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ void __iomem *base = phy->regs;
+
+ val = readl(pmc_base + UTMIP_UHSIC_STATUS);
+
+ /* check whether we wake up from the remote resume */
+ if (UHSIC_WALK_PTR_VAL & val) {
+ phy->remote_wakeup = true;
+ } else {
+ if (!((UHSIC_STROBE_VAL_P0 | UHSIC_DATA_VAL_P0) & val)) {
+ uhsic_phy_disable_pmc_bus_ctrl(phy);
+ } else {
+ DBG("%s(%d): setting pretend connect\n", __func__, __LINE__);
+ val = readl(base + UHSIC_CMD_CFG0);
+ val |= UHSIC_PRETEND_CONNECT_DETECT;
+ writel(val, base + UHSIC_CMD_CFG0);
+ }
+ }
+}
+
+static void uhsic_phy_restore_end(struct tegra_usb_phy *phy)
+{
+
+ unsigned long val;
+ void __iomem *base = phy->regs;
+ int wait_time_us = 3000; /* FPR should be set by this time */
+
+ DBG("%s(%d)\n", __func__, __LINE__);
+
+ /* check whether we wake up from the remote resume */
+ if (phy->remote_wakeup) {
+ /* wait until FPR bit is set automatically on remote resume */
+ do {
+ val = readl(base + USB_PORTSC);
+ udelay(1);
+ if (wait_time_us == 0) {
+ uhsic_phy_disable_pmc_bus_ctrl(phy);
+ uhsic_phy_post_resume(phy);
+ return;
+ }
+ wait_time_us--;
+ } while (!(val & USB_PORTSC_RESUME));
+ /* wait for 25 ms to port resume complete */
+ msleep(25);
+ /* disable PMC master control */
+ uhsic_phy_disable_pmc_bus_ctrl(phy);
+
+ /* Clear PCI and SRI bits to avoid an interrupt upon resume */
+ val = readl(base + USB_USBSTS);
+ writel(val, base + USB_USBSTS);
+ /* wait to avoid SOF if there is any */
+ if (usb_phy_reg_status_wait(base + USB_USBSTS,
+ USB_USBSTS_SRI, USB_USBSTS_SRI, 2500)) {
+ pr_warn("%s: timeout waiting for SOF\n", __func__);
+ }
+ uhsic_phy_post_resume(phy);
+ } else {
+ uhsic_phy_disable_pmc_bus_ctrl(phy);
+ }
+
+ /* Set RUN bit */
+ val = readl(base + USB_USBCMD);
+ val |= USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+ if (usb_phy_reg_status_wait(base + USB_USBCMD, USB_USBCMD_RS,
+ USB_USBCMD_RS, 2000)) {
+ pr_err("%s: timeout waiting for USB_USBCMD_RS\n", __func__);
+ return;
+ }
+}
+
+static int uhsic_phy_open(struct tegra_usb_phy *phy)
+{
+ unsigned long parent_rate;
+ int i;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ parent_rate = clk_get_rate(clk_get_parent(phy->pllu_clk));
+ for (i = 0; i < ARRAY_SIZE(uhsic_freq_table); i++) {
+ if (uhsic_freq_table[i].freq == parent_rate) {
+ phy->freq = &uhsic_freq_table[i];
+ break;
+ }
+ }
+ if (!phy->freq) {
+ pr_err("invalid pll_u parent rate %ld\n", parent_rate);
+ return -EINVAL;
+ }
+
+ uhsic_powerup_pmc_wake_detect(phy);
+
+ return 0;
+}
+
+static int uhsic_phy_irq(struct tegra_usb_phy *phy)
+{
+ usb_phy_fence_read(phy);
+ /* check if there is any remote wake event */
+ if (uhsic_phy_remotewake_detected(phy))
+ pr_info("%s: uhsic remote wake detected\n", __func__);
+ return IRQ_HANDLED;
+}
+
+static int uhsic_phy_power_on(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+ struct tegra_hsic_config *config = &phy->pdata->u_cfg.hsic;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ if (phy->phy_clk_on) {
+ DBG("%s(%d) inst:[%d] phy clk is already On\n",
+ __func__, __LINE__, phy->inst);
+ return 0;
+ }
+
+ val = readl(base + UHSIC_PADS_CFG1);
+ val &= ~(UHSIC_PD_BG | UHSIC_PD_TRK | UHSIC_PD_RX |
+ UHSIC_PD_ZI | UHSIC_RPD_DATA | UHSIC_RPD_STROBE);
+ val |= (UHSIC_RX_SEL | UHSIC_PD_TX);
+ writel(val, base + UHSIC_PADS_CFG1);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= UHSIC_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+ udelay(1);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= UHSIC_PHY_ENABLE;
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + UHSIC_HSRX_CFG0);
+ val |= UHSIC_IDLE_WAIT(config->idle_wait_delay);
+ val |= UHSIC_ELASTIC_UNDERRUN_LIMIT(config->elastic_underrun_limit);
+ val |= UHSIC_ELASTIC_OVERRUN_LIMIT(config->elastic_overrun_limit);
+ writel(val, base + UHSIC_HSRX_CFG0);
+
+ val = readl(base + UHSIC_HSRX_CFG1);
+ val |= UHSIC_HS_SYNC_START_DLY(config->sync_start_delay);
+ writel(val, base + UHSIC_HSRX_CFG1);
+
+ /* WAR HSIC TX */
+ val = readl(base + UHSIC_TX_CFG0);
+ val &= ~UHSIC_HS_READY_WAIT_FOR_VALID;
+ writel(val, base + UHSIC_TX_CFG0);
+
+ val = readl(base + UHSIC_MISC_CFG0);
+ val |= UHSIC_SUSPEND_EXIT_ON_EDGE;
+ /* Disable generic bus reset, to allow AP30 specific bus reset*/
+ val |= UHSIC_DISABLE_BUSRESET;
+ writel(val, base + UHSIC_MISC_CFG0);
+
+ val = readl(base + UHSIC_MISC_CFG1);
+ val |= UHSIC_PLLU_STABLE_COUNT(phy->freq->stable_count);
+ writel(val, base + UHSIC_MISC_CFG1);
+
+ val = readl(base + UHSIC_PLL_CFG1);
+ val |= UHSIC_PLLU_ENABLE_DLY_COUNT(phy->freq->enable_delay);
+ val |= UHSIC_XTAL_FREQ_COUNT(phy->freq->xtal_freq_count);
+ writel(val, base + UHSIC_PLL_CFG1);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~(UHSIC_RESET);
+ writel(val, base + USB_SUSP_CTRL);
+ udelay(1);
+
+ val = readl(base + UHSIC_PADS_CFG1);
+ val &= ~(UHSIC_PD_TX);
+ writel(val, base + UHSIC_PADS_CFG1);
+
+ val = readl(base + USB_USBMODE);
+ val |= USB_USBMODE_HOST;
+ writel(val, base + USB_USBMODE);
+
+ /* Change the USB controller PHY type to HSIC */
+ val = readl(base + HOSTPC1_DEVLC);
+ val &= ~HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_MASK);
+ val |= HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_HSIC);
+ val &= ~HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_MASK);
+ val |= HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_HIGH_SPEED);
+ val &= ~HOSTPC1_DEVLC_STS;
+ writel(val, base + HOSTPC1_DEVLC);
+
+ val = readl(base + USB_TXFILLTUNING);
+ if ((val & USB_FIFO_TXFILL_MASK) != USB_FIFO_TXFILL_THRES(0x10)) {
+ val = USB_FIFO_TXFILL_THRES(0x10);
+ writel(val, base + USB_TXFILLTUNING);
+ }
+
+ val = readl(base + USB_PORTSC);
+ val &= ~(USB_PORTSC_WKOC | USB_PORTSC_WKDS | USB_PORTSC_WKCN);
+ writel(val, base + USB_PORTSC);
+
+ val = readl(base + UHSIC_PADS_CFG0);
+ val &= ~(UHSIC_TX_RTUNEN);
+ /* set Rtune impedance to 50 ohm */
+ val |= UHSIC_TX_RTUNE(8);
+ writel(val, base + UHSIC_PADS_CFG0);
+
+ if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL,
+ USB_PHY_CLK_VALID, USB_PHY_CLK_VALID, 2500)) {
+ pr_err("%s: timeout waiting for phy to stabilize\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ phy->phy_clk_on = true;
+ phy->hw_accessible = true;
+
+ return 0;
+}
+
+static int uhsic_phy_power_off(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (!phy->phy_clk_on) {
+ DBG("%s(%d) inst:[%d] phy clk is already off\n",
+ __func__, __LINE__, phy->inst);
+ return 0;
+ }
+
+ phy->port_speed = (readl(base + HOSTPC1_DEVLC) >> 25) &
+ HOSTPC1_DEVLC_PSPD_MASK;
+
+ /* Disable interrupts */
+ writel(0, base + USB_USBINTR);
+
+ uhsic_setup_pmc_wake_detect(phy);
+
+ val = readl(base + HOSTPC1_DEVLC);
+ val |= HOSTPC1_DEVLC_PHCD;
+ writel(val, base + HOSTPC1_DEVLC);
+
+ phy->phy_clk_on = false;
+ phy->hw_accessible = false;
+
+ return 0;
+}
+
+int uhsic_phy_bus_port_power(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ val = readl(base + USB_USBMODE);
+ val |= USB_USBMODE_HOST;
+ writel(val, base + USB_USBMODE);
+
+ /* Change the USB controller PHY type to HSIC */
+ val = readl(base + HOSTPC1_DEVLC);
+ val &= ~(HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_MASK));
+ val |= HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_HSIC);
+ val &= ~(HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_MASK));
+ val |= HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_HIGH_SPEED);
+ writel(val, base + HOSTPC1_DEVLC);
+
+ val = readl(base + UHSIC_MISC_CFG0);
+ val |= UHSIC_DETECT_SHORT_CONNECT;
+ writel(val, base + UHSIC_MISC_CFG0);
+ udelay(1);
+
+ val = readl(base + UHSIC_MISC_CFG0);
+ val |= UHSIC_FORCE_XCVR_MODE;
+ writel(val, base + UHSIC_MISC_CFG0);
+
+ val = readl(base + UHSIC_PADS_CFG1);
+ val &= ~UHSIC_RPD_STROBE;
+ writel(val, base + UHSIC_PADS_CFG1);
+
+ if (phy->pdata->ops && phy->pdata->ops->port_power)
+ phy->pdata->ops->port_power();
+
+ if (usb_phy_reg_status_wait(base + UHSIC_STAT_CFG0,
+ UHSIC_CONNECT_DETECT, UHSIC_CONNECT_DETECT, 25000)) {
+ pr_err("%s: timeout waiting for UHSIC_CONNECT_DETECT\n",
+ __func__);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int uhsic_phy_bus_reset(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ /* Change the USB controller PHY type to HSIC */
+ val = readl(base + HOSTPC1_DEVLC);
+ val &= ~HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_MASK);
+ val |= HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_HSIC);
+ val &= ~HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_MASK);
+ val |= HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_HIGH_SPEED);
+ val &= ~HOSTPC1_DEVLC_STS;
+ writel(val, base + HOSTPC1_DEVLC);
+ /* wait here, otherwise HOSTPC1_DEVLC_PSPD will timeout */
+ mdelay(5);
+
+ val = readl(base + USB_PORTSC);
+ val |= USB_PORTSC_PTC(5);
+ writel(val, base + USB_PORTSC);
+ udelay(2);
+
+ val = readl(base + USB_PORTSC);
+ val &= ~(USB_PORTSC_PTC(~0));
+ writel(val, base + USB_PORTSC);
+ udelay(2);
+
+ if (usb_phy_reg_status_wait(base + USB_PORTSC, USB_PORTSC_LS(0),
+ 0, 2000)) {
+ pr_err("%s: timeout waiting for USB_PORTSC_LS\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ /* Poll until CCS is enabled */
+ if (usb_phy_reg_status_wait(base + USB_PORTSC, USB_PORTSC_CCS,
+ USB_PORTSC_CCS, 2000)) {
+ pr_err("%s: timeout waiting for USB_PORTSC_CCS\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ if (usb_phy_reg_status_wait(base + HOSTPC1_DEVLC,
+ HOSTPC1_DEVLC_PSPD(2),
+ HOSTPC1_DEVLC_PSPD(2), 2000) < 0) {
+ pr_err("%s: timeout waiting hsic high speed configuration\n",
+ __func__);
+ return -ETIMEDOUT;
+ }
+
+ val = readl(base + USB_USBCMD);
+ val &= ~USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+
+ if (usb_phy_reg_status_wait(base + USB_USBSTS, USB_USBSTS_HCH,
+ USB_USBSTS_HCH, 2000)) {
+ pr_err("%s: timeout waiting for USB_USBSTS_HCH\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ val = readl(base + UHSIC_PADS_CFG1);
+ val &= ~UHSIC_RPU_STROBE;
+ val |= UHSIC_RPD_STROBE;
+ writel(val, base + UHSIC_PADS_CFG1);
+
+ mdelay(50);
+
+ val = readl(base + UHSIC_PADS_CFG1);
+ val &= ~UHSIC_RPD_STROBE;
+ val |= UHSIC_RPU_STROBE;
+ writel(val, base + UHSIC_PADS_CFG1);
+
+ val = readl(base + USB_USBCMD);
+ val |= USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+
+ val = readl(base + UHSIC_PADS_CFG1);
+ val &= ~UHSIC_RPU_STROBE;
+ writel(val, base + UHSIC_PADS_CFG1);
+
+ if (usb_phy_reg_status_wait(base + USB_USBCMD, USB_USBCMD_RS,
+ USB_USBCMD_RS, 2000)) {
+ pr_err("%s: timeout waiting for USB_USBCMD_RS\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+int uhsic_phy_resume(struct tegra_usb_phy *phy)
+{
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ uhsic_phy_restore_start(phy);
+ usb_phy_bringup_host_controller(phy);
+ uhsic_phy_restore_end(phy);
+
+ return 0;
+}
+
+static void ulpi_set_trimmer(struct tegra_usb_phy *phy)
+{
+ struct tegra_ulpi_config *config = &phy->pdata->u_cfg.ulpi;
+ void __iomem *base = phy->regs;
+ unsigned long val;
+
+ val = ULPI_DATA_TRIMMER_SEL(config->data_trimmer);
+ val |= ULPI_STPDIRNXT_TRIMMER_SEL(config->stpdirnxt_trimmer);
+ val |= ULPI_DIR_TRIMMER_SEL(config->dir_trimmer);
+ writel(val, base + ULPI_TIMING_CTRL_1);
+ udelay(10);
+
+ val |= ULPI_DATA_TRIMMER_LOAD;
+ val |= ULPI_STPDIRNXT_TRIMMER_LOAD;
+ val |= ULPI_DIR_TRIMMER_LOAD;
+ writel(val, base + ULPI_TIMING_CTRL_1);
+}
+
+static void reset_utmip_uhsic(void __iomem *base)
+{
+ unsigned long val;
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= UHSIC_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= UTMIP_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+}
+
+static void ulpi_set_host(void __iomem *base)
+{
+ unsigned long val;
+
+ val = readl(base + USB_USBMODE);
+ val &= ~USB_USBMODE_MASK;
+ val |= USB_USBMODE_HOST;
+ writel(val, base + USB_USBMODE);
+
+ val = readl(base + HOSTPC1_DEVLC);
+ val |= HOSTPC1_DEVLC_PTS(2);
+ writel(val, base + HOSTPC1_DEVLC);
+}
+
+static inline void ulpi_pinmux_bypass(struct tegra_usb_phy *phy, bool enable)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ val = readl(base + ULPI_TIMING_CTRL_0);
+
+ if (enable)
+ val |= ULPI_OUTPUT_PINMUX_BYP;
+ else
+ val &= ~ULPI_OUTPUT_PINMUX_BYP;
+
+ writel(val, base + ULPI_TIMING_CTRL_0);
+}
+
+static inline void ulpi_null_phy_set_tristate(bool enable)
+{
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+ int tristate = (enable) ? TEGRA_TRI_TRISTATE : TEGRA_TRI_NORMAL;
+
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA0, tristate);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA1, tristate);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA2, tristate);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA3, tristate);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA4, tristate);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA5, tristate);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA6, tristate);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA7, tristate);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_NXT, tristate);
+
+ if (enable)
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DIR, tristate);
+#endif
+}
+
+static void ulpi_null_phy_obs_read(void)
+{
+ static void __iomem *apb_misc;
+ unsigned slv0_obs, s2s_obs;
+
+ if (!apb_misc)
+ apb_misc = ioremap(TEGRA_APB_MISC_BASE, TEGRA_APB_MISC_SIZE);
+
+ writel(0x80d1003c, apb_misc + APB_MISC_GP_OBSCTRL_0);
+ slv0_obs = readl(apb_misc + APB_MISC_GP_OBSDATA_0);
+
+ writel(0x80d10040, apb_misc + APB_MISC_GP_OBSCTRL_0);
+ s2s_obs = readl(apb_misc + APB_MISC_GP_OBSDATA_0);
+
+ pr_debug("slv0 obs: %08x\ns2s obs: %08x\n", slv0_obs, s2s_obs);
+}
+
+static const struct gpio ulpi_gpios[] = {
+ {ULPI_STP, GPIOF_IN, "ULPI_STP"},
+ {ULPI_DIR, GPIOF_OUT_INIT_LOW, "ULPI_DIR"},
+ {ULPI_D0, GPIOF_OUT_INIT_LOW, "ULPI_D0"},
+ {ULPI_D1, GPIOF_OUT_INIT_LOW, "ULPI_D1"},
+};
+
+static int ulpi_null_phy_open(struct tegra_usb_phy *phy)
+{
+ struct tegra_ulpi_config *config = &phy->pdata->u_cfg.ulpi;
+ int ret;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ ret = gpio_request_array(ulpi_gpios, ARRAY_SIZE(ulpi_gpios));
+ if (ret)
+ return ret;
+
+ if (gpio_is_valid(config->phy_restore_gpio)) {
+ ret = gpio_request(config->phy_restore_gpio, "phy_restore");
+ if (ret)
+ goto err_gpio_free;
+
+ gpio_direction_input(config->phy_restore_gpio);
+ }
+
+ tegra_periph_reset_assert(phy->ctrlr_clk);
+ udelay(10);
+ tegra_periph_reset_deassert(phy->ctrlr_clk);
+
+ return 0;
+
+err_gpio_free:
+ gpio_free_array(ulpi_gpios, ARRAY_SIZE(ulpi_gpios));
+ return ret;
+}
+
+static void ulpi_null_phy_close(struct tegra_usb_phy *phy)
+{
+ struct tegra_ulpi_config *config = &phy->pdata->u_cfg.ulpi;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ if (gpio_is_valid(config->phy_restore_gpio))
+ gpio_free(config->phy_restore_gpio);
+
+ gpio_free_array(ulpi_gpios, ARRAY_SIZE(ulpi_gpios));
+}
+
+static int ulpi_null_phy_power_off(struct tegra_usb_phy *phy)
+{
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ if (!phy->phy_clk_on) {
+ DBG("%s(%d) inst:[%d] phy clk is already off\n", __func__,
+ __LINE__, phy->inst);
+ return 0;
+ }
+
+ phy->phy_clk_on = false;
+ phy->hw_accessible = false;
+ ulpi_null_phy_set_tristate(true);
+ return 0;
+}
+
+/* NOTE: this function must be called before ehci reset */
+static int ulpi_null_phy_init(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ val = readl(base + ULPIS2S_CTRL);
+ val |= ULPIS2S_SLV0_CLAMP_XMIT;
+ writel(val, base + ULPIS2S_CTRL);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= ULPIS2S_SLV0_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+ udelay(10);
+
+ return 0;
+}
+
+static int ulpi_null_phy_irq(struct tegra_usb_phy *phy)
+{
+ usb_phy_fence_read(phy);
+ return IRQ_HANDLED;
+}
+
+/* NOTE: this function must be called after ehci reset */
+static int ulpi_null_phy_cmd_reset(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ ulpi_set_host(base);
+
+ /* remove slave0 reset */
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~ULPIS2S_SLV0_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + ULPIS2S_CTRL);
+ val &= ~ULPIS2S_SLV0_CLAMP_XMIT;
+ writel(val, base + ULPIS2S_CTRL);
+ udelay(10);
+
+ return 0;
+}
+
+static int ulpi_null_phy_restore(struct tegra_usb_phy *phy)
+{
+ struct tegra_ulpi_config *config = &phy->pdata->u_cfg.ulpi;
+ unsigned long timeout;
+ int ulpi_stp = ULPI_STP;
+
+ if (gpio_is_valid(config->phy_restore_gpio))
+ ulpi_stp = config->phy_restore_gpio;
+
+ /* disable ULPI pinmux bypass */
+ ulpi_pinmux_bypass(phy, false);
+
+ /* driving linstate by GPIO */
+ gpio_set_value(ULPI_D0, 0);
+ gpio_set_value(ULPI_D1, 0);
+
+ /* driving DIR high */
+ gpio_set_value(ULPI_DIR, 1);
+
+ /* remove ULPI tristate */
+ ulpi_null_phy_set_tristate(false);
+
+ /* wait for STP high */
+ timeout = jiffies + msecs_to_jiffies(25);
+
+ while (!gpio_get_value(ulpi_stp)) {
+ if (time_after(jiffies, timeout)) {
+ pr_warn("phy restore timeout\n");
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int ulpi_null_phy_lp0_resume(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ ulpi_null_phy_init(phy);
+
+ val = readl(base + USB_USBCMD);
+ val |= USB_CMD_RESET;
+ writel(val, base + USB_USBCMD);
+
+ if (usb_phy_reg_status_wait(base + USB_USBCMD,
+ USB_CMD_RESET, 0, 2500) < 0) {
+ pr_err("%s: timeout waiting for reset\n", __func__);
+ }
+
+ ulpi_null_phy_cmd_reset(phy);
+
+ val = readl(base + USB_USBCMD);
+ val |= USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+ if (usb_phy_reg_status_wait(base + USB_USBCMD, USB_USBCMD_RS,
+ USB_USBCMD_RS, 2000)) {
+ pr_err("%s: timeout waiting for USB_USBCMD_RS\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ /* Enable Port Power */
+ val = readl(base + USB_PORTSC);
+ val |= USB_PORTSC_PP;
+ writel(val, base + USB_PORTSC);
+ udelay(10);
+
+ ulpi_null_phy_restore(phy);
+
+ return 0;
+}
+
+static int ulpi_null_phy_power_on(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+ struct tegra_ulpi_config *config = &phy->pdata->u_cfg.ulpi;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (phy->phy_clk_on) {
+ DBG("%s(%d) inst:[%d] phy clk is already On\n", __func__,
+ __LINE__, phy->inst);
+ return 0;
+ }
+ reset_utmip_uhsic(base);
+
+ /* remove ULPI PADS CLKEN reset */
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~ULPI_PADS_CLKEN_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+ udelay(10);
+
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_OUTPUT_PINMUX_BYP | ULPI_CLKOUT_PINMUX_BYP;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= ULPI_PHY_ENABLE;
+ writel(val, base + USB_SUSP_CTRL);
+ udelay(10);
+
+ /* set timming parameters */
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_SHADOW_CLK_LOOPBACK_EN;
+ val &= ~ULPI_SHADOW_CLK_SEL;
+ val &= ~ULPI_LBK_PAD_EN;
+ val |= ULPI_SHADOW_CLK_DELAY(config->shadow_clk_delay);
+ val |= ULPI_CLOCK_OUT_DELAY(config->clock_out_delay);
+ val |= ULPI_LBK_PAD_E_INPUT_OR;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+
+ writel(0, base + ULPI_TIMING_CTRL_1);
+ udelay(10);
+
+ /* start internal 60MHz clock */
+ val = readl(base + ULPIS2S_CTRL);
+ val |= ULPIS2S_ENA;
+ val |= ULPIS2S_SUPPORT_DISCONNECT;
+ val |= ULPIS2S_SPARE((phy->pdata->op_mode == TEGRA_USB_OPMODE_HOST) ? 3 : 1);
+ val |= ULPIS2S_PLLU_MASTER_BLASTER60;
+ writel(val, base + ULPIS2S_CTRL);
+
+ /* select ULPI_CORE_CLK_SEL to SHADOW_CLK */
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_CORE_CLK_SEL;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+ udelay(10);
+
+ /* enable ULPI null phy clock - can't set the trimmers before this */
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_CLK_OUT_ENA;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+ udelay(10);
+
+ if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID,
+ USB_PHY_CLK_VALID, 2500)) {
+ pr_err("%s: timeout waiting for phy to stabilize\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ /* set ULPI trimmers */
+ ulpi_set_trimmer(phy);
+
+ ulpi_set_host(base);
+
+ /* remove slave0 reset */
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~ULPIS2S_SLV0_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+
+ /* remove slave1 and line reset */
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~ULPIS2S_SLV1_RESET;
+ val &= ~ULPIS2S_LINE_RESET;
+
+ /* remove ULPI PADS reset */
+ val &= ~ULPI_PADS_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+
+ if (!phy->ulpi_clk_padout_ena) {
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_CLK_PADOUT_ENA;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+ phy->ulpi_clk_padout_ena = true;
+ } else {
+ if (!readl(base + USB_ASYNCLISTADDR))
+ ulpi_null_phy_lp0_resume(phy);
+ }
+ udelay(10);
+
+ phy->phy_clk_on = true;
+ phy->hw_accessible = true;
+
+ return 0;
+}
+
+static int ulpi_null_phy_pre_resume(struct tegra_usb_phy *phy,
+ bool remote_wakeup)
+{
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ ulpi_null_phy_obs_read();
+ usb_phy_wait_for_sof(phy);
+ ulpi_null_phy_obs_read();
+ return 0;
+}
+
+static int ulpi_null_phy_post_resume(struct tegra_usb_phy *phy)
+{
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ ulpi_null_phy_obs_read();
+ return 0;
+}
+
+static int ulpi_null_phy_resume(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ if (!readl(base + USB_ASYNCLISTADDR)) {
+ /* enable ULPI CLK output pad */
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_CLK_PADOUT_ENA;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+
+ /* enable ULPI pinmux bypass */
+ ulpi_pinmux_bypass(phy, true);
+ udelay(5);
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+ /* remove DIR tristate */
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DIR,
+ TEGRA_TRI_NORMAL);
+#endif
+ }
+ return 0;
+}
+
+
+
+static struct tegra_usb_phy_ops utmi_phy_ops = {
+ .open = utmi_phy_open,
+ .close = utmi_phy_close,
+ .irq = utmi_phy_irq,
+ .power_on = utmi_phy_power_on,
+ .power_off = utmi_phy_power_off,
+ .pre_resume = utmi_phy_pre_resume,
+ .resume = utmi_phy_resume,
+ .post_resume = utmi_phy_post_resume,
+ .charger_detect = utmi_phy_charger_detect,
+};
+
+static struct tegra_usb_phy_ops uhsic_phy_ops = {
+ .open = uhsic_phy_open,
+ .irq = uhsic_phy_irq,
+ .power_on = uhsic_phy_power_on,
+ .power_off = uhsic_phy_power_off,
+ .pre_resume = uhsic_phy_pre_resume,
+ .resume = uhsic_phy_resume,
+ .post_resume = uhsic_phy_post_resume,
+ .port_power = uhsic_phy_bus_port_power,
+ .bus_reset = uhsic_phy_bus_reset,
+};
+
+static struct tegra_usb_phy_ops ulpi_null_phy_ops = {
+ .open = ulpi_null_phy_open,
+ .close = ulpi_null_phy_close,
+ .init = ulpi_null_phy_init,
+ .irq = ulpi_null_phy_irq,
+ .power_on = ulpi_null_phy_power_on,
+ .power_off = ulpi_null_phy_power_off,
+ .pre_resume = ulpi_null_phy_pre_resume,
+ .resume = ulpi_null_phy_resume,
+ .post_resume = ulpi_null_phy_post_resume,
+ .reset = ulpi_null_phy_cmd_reset,
+};
+
+static struct tegra_usb_phy_ops ulpi_link_phy_ops;
+static struct tegra_usb_phy_ops icusb_phy_ops;
+
+static struct tegra_usb_phy_ops *phy_ops[] = {
+ [TEGRA_USB_PHY_INTF_UTMI] = &utmi_phy_ops,
+ [TEGRA_USB_PHY_INTF_ULPI_LINK] = &ulpi_link_phy_ops,
+ [TEGRA_USB_PHY_INTF_ULPI_NULL] = &ulpi_null_phy_ops,
+ [TEGRA_USB_PHY_INTF_HSIC] = &uhsic_phy_ops,
+ [TEGRA_USB_PHY_INTF_ICUSB] = &icusb_phy_ops,
+};
+
+int tegra3_usb_phy_init_ops(struct tegra_usb_phy *phy)
+{
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ phy->ops = phy_ops[phy->pdata->phy_intf];
+
+ /* FIXME: uncommenting below line to make USB host mode fail*/
+ /* usb_phy_power_down_pmc(); */
+
+ return 0;
+}
diff --git a/arch/arm/mach-tegra/tegra_odm_fuses.c b/arch/arm/mach-tegra/tegra_odm_fuses.c
index 5dcf24e497b2..06b831c31967 100644
--- a/arch/arm/mach-tegra/tegra_odm_fuses.c
+++ b/arch/arm/mach-tegra/tegra_odm_fuses.c
@@ -885,7 +885,7 @@ static ssize_t fuse_show(struct kobject *kobj, struct kobj_attribute *attr, char
{
enum fuse_io_param param = fuse_name_to_param(attr->attr.name);
u32 data[8];
- char str[8];
+ char str[9]; /* extra byte for null character */
int ret, i;
if ((param == -1) || (param == -ENODATA)) {
diff --git a/arch/arm/mach-tegra/tegra_usb_modem_power.c b/arch/arm/mach-tegra/tegra_usb_modem_power.c
index 88543397f974..bb9495a329a6 100644
--- a/arch/arm/mach-tegra/tegra_usb_modem_power.c
+++ b/arch/arm/mach-tegra/tegra_usb_modem_power.c
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/tegra_usb_modem_power.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
@@ -22,6 +22,7 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
+#include <linux/platform_data/tegra_usb.h>
#include <linux/workqueue.h>
#include <linux/gpio.h>
#include <linux/usb.h>
@@ -30,27 +31,46 @@
#include <linux/suspend.h>
#include <linux/slab.h>
#include <linux/wakelock.h>
+#include <linux/pm_qos_params.h>
#include <mach/tegra_usb_modem_power.h>
+#define BOOST_CPU_FREQ_MIN 1200000
+#define BOOST_CPU_FREQ_TIMEOUT 5000
+
+#define WAKELOCK_TIMEOUT_FOR_USB_ENUM (HZ * 10)
+#define WAKELOCK_TIMEOUT_FOR_REMOTE_WAKE (HZ)
+
struct tegra_usb_modem {
- unsigned int wake_gpio; /* remote wakeup gpio */
+ struct tegra_usb_modem_power_platform_data *pdata;
unsigned int wake_cnt; /* remote wakeup counter */
- int irq; /* remote wakeup irq */
+ unsigned int wake_irq; /* remote wakeup irq */
+ unsigned int boot_irq; /* modem boot irq */
struct mutex lock;
struct wake_lock wake_lock; /* modem wake lock */
unsigned int vid; /* modem vendor id */
unsigned int pid; /* modem product id */
struct usb_device *udev; /* modem usb device */
+ struct usb_device *parent; /* parent device */
struct usb_interface *intf; /* first modem usb interface */
struct workqueue_struct *wq; /* modem workqueue */
struct delayed_work recovery_work; /* modem recovery work */
+ struct pm_qos_request_list cpu_boost_req; /* min CPU freq request */
+ struct work_struct cpu_boost_work; /* CPU freq boost work */
+ struct delayed_work cpu_unboost_work; /* CPU freq unboost work */
const struct tegra_modem_operations *ops; /* modem operations */
unsigned int capability; /* modem capability */
int system_suspend; /* system suspend flag */
struct notifier_block pm_notifier; /* pm event notifier */
struct notifier_block usb_notifier; /* usb event notifier */
+ int sysfs_file_created;
+ int short_autosuspend_enabled;
};
+static struct platform_device *hc = NULL; /* USB host controller */
+static struct mutex hc_lock;
+static const struct platform_device *hc_device;
+static const struct tegra_usb_platform_data *hc_pdata;
+
/* supported modems */
static const struct usb_device_id modem_list[] = {
{USB_DEVICE(0x1983, 0x0310), /* Icera 450 rev1 */
@@ -65,27 +85,81 @@ static const struct usb_device_id modem_list[] = {
{}
};
+static void cpu_freq_unboost(struct work_struct *ws)
+{
+ struct tegra_usb_modem *modem = container_of(ws, struct tegra_usb_modem,
+ cpu_unboost_work.work);
+
+ pm_qos_update_request(&modem->cpu_boost_req, PM_QOS_DEFAULT_VALUE);
+}
+
+static void cpu_freq_boost(struct work_struct *ws)
+{
+ struct tegra_usb_modem *modem = container_of(ws, struct tegra_usb_modem,
+ cpu_boost_work);
+
+ cancel_delayed_work_sync(&modem->cpu_unboost_work);
+ pm_qos_update_request(&modem->cpu_boost_req, BOOST_CPU_FREQ_MIN);
+ queue_delayed_work(modem->wq, &modem->cpu_unboost_work,
+ msecs_to_jiffies(BOOST_CPU_FREQ_TIMEOUT));
+}
+
static irqreturn_t tegra_usb_modem_wake_thread(int irq, void *data)
{
struct tegra_usb_modem *modem = (struct tegra_usb_modem *)data;
- wake_lock_timeout(&modem->wake_lock, HZ);
mutex_lock(&modem->lock);
- if (modem->udev) {
+ if (modem->udev && modem->udev->state != USB_STATE_NOTATTACHED) {
pr_info("modem wake (%u)\n", ++(modem->wake_cnt));
if (!modem->system_suspend) {
+ wake_lock_timeout(&modem->wake_lock,
+ WAKELOCK_TIMEOUT_FOR_REMOTE_WAKE);
+
usb_lock_device(modem->udev);
if (usb_autopm_get_interface(modem->intf) == 0)
usb_autopm_put_interface_async(modem->intf);
usb_unlock_device(modem->udev);
}
+#ifdef CONFIG_PM
+ if (modem->capability & TEGRA_MODEM_AUTOSUSPEND &&
+ modem->short_autosuspend_enabled) {
+ pm_runtime_set_autosuspend_delay(&modem->udev->dev,
+ modem->pdata->autosuspend_delay);
+ modem->short_autosuspend_enabled = 0;
+ }
+#endif
}
mutex_unlock(&modem->lock);
return IRQ_HANDLED;
}
+static irqreturn_t tegra_usb_modem_boot_thread(int irq, void *data)
+{
+ struct tegra_usb_modem *modem = (struct tegra_usb_modem *)data;
+
+ if (gpio_get_value(modem->pdata->boot_gpio))
+ pr_info("BB_RST_OUT high\n");
+ else
+ pr_info("BB_RST_OUT low\n");
+
+ /* hold wait lock to complete the enumeration */
+ wake_lock_timeout(&modem->wake_lock, WAKELOCK_TIMEOUT_FOR_USB_ENUM);
+
+ /* boost CPU freq */
+ if (!work_pending(&modem->cpu_boost_work))
+ queue_work(modem->wq, &modem->cpu_boost_work);
+
+ /* USB disconnect maybe on going... */
+ mutex_lock(&modem->lock);
+ if (modem->udev && modem->udev->state != USB_STATE_NOTATTACHED)
+ pr_warn("Device is not disconnected!\n");
+ mutex_unlock(&modem->lock);
+
+ return IRQ_HANDLED;
+}
+
static void tegra_usb_modem_recovery(struct work_struct *ws)
{
struct tegra_usb_modem *modem = container_of(ws, struct tegra_usb_modem,
@@ -108,13 +182,15 @@ static void device_add_handler(struct tegra_usb_modem *modem,
if (id) {
/* hold wakelock to ensure ril has enough time to restart */
- wake_lock_timeout(&modem->wake_lock, HZ * 10);
+ wake_lock_timeout(&modem->wake_lock,
+ WAKELOCK_TIMEOUT_FOR_USB_ENUM);
pr_info("Add device %d <%s %s>\n", udev->devnum,
udev->manufacturer, udev->product);
mutex_lock(&modem->lock);
modem->udev = udev;
+ modem->parent = udev->parent;
modem->intf = intf;
modem->vid = desc->idVendor;
modem->pid = desc->idProduct;
@@ -126,7 +202,9 @@ static void device_add_handler(struct tegra_usb_modem *modem,
#ifdef CONFIG_PM
if (modem->capability & TEGRA_MODEM_AUTOSUSPEND) {
- pm_runtime_set_autosuspend_delay(&udev->dev, 2000);
+ pm_runtime_set_autosuspend_delay(&udev->dev,
+ modem->pdata->autosuspend_delay);
+ modem->short_autosuspend_enabled = 0;
usb_enable_autosuspend(udev);
pr_info("enable autosuspend for %s %s\n",
udev->manufacturer, udev->product);
@@ -140,8 +218,7 @@ static void device_remove_handler(struct tegra_usb_modem *modem,
{
const struct usb_device_descriptor *desc = &udev->descriptor;
- if (desc->idVendor == modem->vid &&
- desc->idProduct == modem->pid) {
+ if (desc->idVendor == modem->vid && desc->idProduct == modem->pid) {
pr_info("Remove device %d <%s %s>\n", udev->devnum,
udev->manufacturer, udev->product);
@@ -158,11 +235,10 @@ static void device_remove_handler(struct tegra_usb_modem *modem,
}
static int mdm_usb_notifier(struct notifier_block *notifier,
- unsigned long usb_event,
- void *udev)
+ unsigned long usb_event, void *udev)
{
struct tegra_usb_modem *modem =
- container_of(notifier, struct tegra_usb_modem, usb_notifier);
+ container_of(notifier, struct tegra_usb_modem, usb_notifier);
switch (usb_event) {
case USB_DEVICE_ADD:
@@ -176,11 +252,10 @@ static int mdm_usb_notifier(struct notifier_block *notifier,
}
static int mdm_pm_notifier(struct notifier_block *notifier,
- unsigned long pm_event,
- void *unused)
+ unsigned long pm_event, void *unused)
{
struct tegra_usb_modem *modem =
- container_of(notifier, struct tegra_usb_modem, pm_notifier);
+ container_of(notifier, struct tegra_usb_modem, pm_notifier);
mutex_lock(&modem->lock);
if (!modem->udev) {
@@ -194,10 +269,20 @@ static int mdm_pm_notifier(struct notifier_block *notifier,
if (wake_lock_active(&modem->wake_lock)) {
pr_warn("%s: wakelock was active, aborting suspend\n",
__func__);
+ mutex_unlock(&modem->lock);
return NOTIFY_STOP;
}
modem->system_suspend = 1;
+#ifdef CONFIG_PM
+ if (modem->capability & TEGRA_MODEM_AUTOSUSPEND &&
+ modem->udev &&
+ modem->udev->state != USB_STATE_NOTATTACHED) {
+ pm_runtime_set_autosuspend_delay(&modem->udev->dev,
+ modem->pdata->short_autosuspend_delay);
+ modem->short_autosuspend_enabled = 1;
+ }
+#endif
mutex_unlock(&modem->lock);
return NOTIFY_OK;
case PM_POST_SUSPEND:
@@ -210,12 +295,125 @@ static int mdm_pm_notifier(struct notifier_block *notifier,
return NOTIFY_DONE;
}
+static int mdm_request_wakeable_irq(struct tegra_usb_modem *modem,
+ irq_handler_t thread_fn,
+ unsigned int irq_gpio,
+ unsigned long irq_flags,
+ const char *label, unsigned int *irq)
+{
+ int ret;
+
+ ret = gpio_request(irq_gpio, label);
+ if (ret)
+ return ret;
+
+ tegra_gpio_enable(irq_gpio);
+
+ /* enable IRQ for GPIO */
+ *irq = gpio_to_irq(irq_gpio);
+
+ /* request threaded irq for GPIO */
+ ret = request_threaded_irq(*irq, NULL, thread_fn, irq_flags, label,
+ modem);
+ if (ret)
+ return ret;
+
+ ret = enable_irq_wake(*irq);
+ if (ret) {
+ free_irq(*irq, modem);
+ return ret;
+ }
+
+ return ret;
+}
+
+/* load USB host controller */
+static struct platform_device *tegra_usb_null_ulpi_host_register(void)
+{
+ struct platform_device *pdev;
+ int val;
+
+ pdev = platform_device_alloc(hc_device->name, hc_device->id);
+ if (!pdev)
+ return NULL;
+
+ val = platform_device_add_resources(pdev, hc_device->resource,
+ hc_device->num_resources);
+ if (val)
+ goto error;
+
+ pdev->dev.dma_mask = hc_device->dev.dma_mask;
+ pdev->dev.coherent_dma_mask = hc_device->dev.coherent_dma_mask;
+
+ val = platform_device_add_data(pdev, hc_pdata,
+ sizeof(struct tegra_usb_platform_data));
+ if (val)
+ goto error;
+
+ val = platform_device_add(pdev);
+ if (val)
+ goto error;
+
+ return pdev;
+
+error:
+ pr_err("%s: err %d\n", __func__, val);
+ platform_device_put(pdev);
+ return NULL;
+}
+
+/* unload USB host controller */
+static void tegra_usb_null_ulpi_host_unregister(struct platform_device *pdev)
+{
+ platform_device_unregister(pdev);
+}
+
+static ssize_t show_usb_host(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", (hc) ? 1 : 0);
+}
+
+static ssize_t load_unload_usb_host(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int host;
+
+ if (sscanf(buf, "%d", &host) != 1 || host < 0 || host > 1)
+ return -EINVAL;
+
+ pr_info("%s USB host\n", (host) ? "load" : "unload");
+
+ mutex_lock(&hc_lock);
+ if (host) {
+ if (!hc)
+ hc = tegra_usb_null_ulpi_host_register();
+ } else {
+ if (hc) {
+ tegra_usb_null_ulpi_host_unregister(hc);
+ hc = NULL;
+ }
+ }
+ mutex_unlock(&hc_lock);
+
+ return count;
+}
+
+static DEVICE_ATTR(load_host, 0666, show_usb_host, load_unload_usb_host);
+
static int mdm_init(struct tegra_usb_modem *modem, struct platform_device *pdev)
{
struct tegra_usb_modem_power_platform_data *pdata =
pdev->dev.platform_data;
int ret = 0;
+ modem->pdata = pdata;
+
+ hc_device = pdata->tegra_ehci_device;
+ hc_pdata = pdata->tegra_ehci_pdata;
+ mutex_init(&hc_lock);
+
/* get modem operations from platform data */
modem->ops = (const struct tegra_modem_operations *)pdata->ops;
@@ -232,46 +430,47 @@ static int mdm_init(struct tegra_usb_modem *modem, struct platform_device *pdev)
modem->ops->start();
}
+ /* create sysfs node to load/unload host controller */
+ ret = device_create_file(&pdev->dev, &dev_attr_load_host);
+ if (ret) {
+ dev_err(&pdev->dev, "can't create sysfs file\n");
+ goto error;
+ }
+ modem->sysfs_file_created = 1;
+
mutex_init(&(modem->lock));
- wake_lock_init(&modem->wake_lock, WAKE_LOCK_SUSPEND,
- "tegra_usb_mdm_lock");
+ wake_lock_init(&modem->wake_lock, WAKE_LOCK_SUSPEND, "mdm_lock");
- /* create work queue platform_driver_registe*/
+ /* create work queue platform_driver_registe */
modem->wq = create_workqueue("tegra_usb_mdm_queue");
- INIT_DELAYED_WORK(&(modem->recovery_work), tegra_usb_modem_recovery);
+ INIT_DELAYED_WORK(&modem->recovery_work, tegra_usb_modem_recovery);
- /* create threaded irq for remote wakeup */
- if (gpio_is_valid(pdata->wake_gpio)) {
- /* get remote wakeup gpio from platform data */
- modem->wake_gpio = pdata->wake_gpio;
+ INIT_WORK(&modem->cpu_boost_work, cpu_freq_boost);
+ INIT_DELAYED_WORK(&modem->cpu_unboost_work, cpu_freq_unboost);
- ret = gpio_request(modem->wake_gpio, "usb_mdm_wake");
- if (ret)
- return ret;
+ pm_qos_add_request(&modem->cpu_boost_req, PM_QOS_CPU_FREQ_MIN,
+ PM_QOS_DEFAULT_VALUE);
- tegra_gpio_enable(modem->wake_gpio);
-
- /* enable IRQ for remote wakeup */
- modem->irq = gpio_to_irq(modem->wake_gpio);
-
- ret =
- request_threaded_irq(modem->irq, NULL,
- tegra_usb_modem_wake_thread,
- pdata->flags, "tegra_usb_mdm_wake",
- modem);
- if (ret < 0) {
- dev_err(&pdev->dev, "%s: request_threaded_irq error\n",
- __func__);
- return ret;
- }
+ /* request remote wakeup irq from platform data */
+ ret = mdm_request_wakeable_irq(modem,
+ tegra_usb_modem_wake_thread,
+ pdata->wake_gpio,
+ pdata->wake_irq_flags,
+ "mdm_wake", &modem->wake_irq);
+ if (ret) {
+ dev_err(&pdev->dev, "request wake irq error\n");
+ goto error;
+ }
- ret = enable_irq_wake(modem->irq);
- if (ret) {
- dev_err(&pdev->dev, "%s: enable_irq_wake error\n",
- __func__);
- free_irq(modem->irq, modem);
- return ret;
- }
+ /* request boot irq from platform data */
+ ret = mdm_request_wakeable_irq(modem,
+ tegra_usb_modem_boot_thread,
+ pdata->boot_gpio,
+ pdata->boot_irq_flags,
+ "mdm_boot", &modem->boot_irq);
+ if (ret) {
+ dev_err(&pdev->dev, "request boot irq error\n");
+ goto error;
}
modem->pm_notifier.notifier_call = mdm_pm_notifier;
@@ -281,6 +480,21 @@ static int mdm_init(struct tegra_usb_modem *modem, struct platform_device *pdev)
register_pm_notifier(&modem->pm_notifier);
return ret;
+error:
+ if (modem->sysfs_file_created)
+ device_remove_file(&pdev->dev, &dev_attr_load_host);
+
+ if (modem->wake_irq) {
+ disable_irq_wake(modem->wake_irq);
+ free_irq(modem->wake_irq, modem);
+ }
+
+ if (modem->boot_irq) {
+ disable_irq_wake(modem->boot_irq);
+ free_irq(modem->boot_irq, modem);
+ }
+
+ return ret;
}
static int tegra_usb_modem_probe(struct platform_device *pdev)
@@ -319,10 +533,25 @@ static int __exit tegra_usb_modem_remove(struct platform_device *pdev)
unregister_pm_notifier(&modem->pm_notifier);
usb_unregister_notify(&modem->usb_notifier);
- if (modem->irq) {
- disable_irq_wake(modem->irq);
- free_irq(modem->irq, modem);
+ if (modem->wake_irq) {
+ disable_irq_wake(modem->wake_irq);
+ free_irq(modem->wake_irq, modem);
}
+
+ if (modem->boot_irq) {
+ disable_irq_wake(modem->boot_irq);
+ free_irq(modem->boot_irq, modem);
+ }
+
+ if (modem->sysfs_file_created)
+ device_remove_file(&pdev->dev, &dev_attr_load_host);
+
+ cancel_work_sync(&modem->cpu_boost_work);
+ cancel_delayed_work_sync(&modem->cpu_unboost_work);
+ destroy_workqueue(modem->wq);
+
+ pm_qos_remove_request(&modem->cpu_boost_req);
+
kfree(modem);
return 0;
}
diff --git a/arch/arm/mach-tegra/tegra_usb_phy.h b/arch/arm/mach-tegra/tegra_usb_phy.h
new file mode 100644
index 000000000000..0dc4cd73c5e7
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra_usb_phy.h
@@ -0,0 +1,107 @@
+/*
+ * arch/arm/mach-tegra/include/mach/tegra_usb_phy.h
+ *
+ * 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
+ * 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 __MACH_TEGRA_USB_PHY_H
+#define __MACH_TEGRA_USB_PHY_H
+
+/**
+ * defines USB port speeds supported in USB2.0
+ */
+enum usb_phy_port_speed {
+ USB_PHY_PORT_SPEED_FULL = 0,
+ USB_PHY_PORT_SPEED_LOW,
+ USB_PHY_PORT_SPEED_HIGH,
+ USB_PHY_PORT_SPEED_UNKNOWN,
+};
+
+/**
+ * defines structure for oscillator dependent parameters
+ */
+struct tegra_xtal_freq {
+ int freq;
+ u8 enable_delay;
+ u8 stable_count;
+ u8 active_delay;
+ u16 xtal_freq_count;
+ u16 debounce;
+ u8 pdtrk_count;
+};
+
+/**
+ * pre decleration of the usb phy data structure
+ */
+struct tegra_usb_phy;
+
+/**
+ * defines function pointers used for differnt phy interfaces
+ */
+struct tegra_usb_phy_ops {
+ int (*open)(struct tegra_usb_phy *phy);
+ void (*close)(struct tegra_usb_phy *phy);
+ int (*irq)(struct tegra_usb_phy *phy);
+ int (*init)(struct tegra_usb_phy *phy);
+ int (*reset)(struct tegra_usb_phy *phy);
+ int (*pre_suspend)(struct tegra_usb_phy *phy);
+ int (*suspend)(struct tegra_usb_phy *phy);
+ int (*post_suspend)(struct tegra_usb_phy *phy);
+ int (*pre_resume)(struct tegra_usb_phy *phy, bool remote_wakeup);
+ int (*resume)(struct tegra_usb_phy *phy);
+ int (*post_resume)(struct tegra_usb_phy *phy);
+ int (*port_power)(struct tegra_usb_phy *phy);
+ int (*bus_reset)(struct tegra_usb_phy *phy);
+ int (*power_off)(struct tegra_usb_phy *phy);
+ int (*power_on)(struct tegra_usb_phy *phy);
+ bool (*charger_detect)(struct tegra_usb_phy *phy);
+};
+
+/**
+ * defines usb phy data structure
+ */
+struct tegra_usb_phy {
+ struct platform_device *pdev;
+ struct tegra_usb_platform_data *pdata;
+ struct clk *pllu_clk;
+ struct clk *ctrlr_clk;
+ struct clk *ulpi_clk;
+ struct clk *utmi_pad_clk;
+ struct clk *emc_clk;
+ struct clk *sys_clk;
+ struct regulator *vdd_reg;
+ struct regulator *vbus_reg;
+ struct tegra_usb_phy_ops *ops;
+ struct tegra_xtal_freq *freq;
+ struct otg_transceiver *ulpi_vp;
+ enum usb_phy_port_speed port_speed;
+ signed char utmi_xcvr_setup;
+ void __iomem *regs;
+ int inst;
+ bool phy_clk_on;
+ bool ctrl_clk_on;
+ bool vdd_reg_on;
+ bool phy_power_on;
+ bool remote_wakeup;
+ bool hw_accessible;
+ bool ulpi_clk_padout_ena;
+};
+
+int usb_phy_reg_status_wait(void __iomem *reg, u32 mask,
+ u32 result, u32 timeout);
+
+int tegra3_usb_phy_init_ops(struct tegra_usb_phy *phy);
+int tegra2_usb_phy_init_ops(struct tegra_usb_phy *phy);
+
+
+#endif /* __MACH_TEGRA_USB_PHY_H */
diff --git a/arch/arm/mach-tegra/timer-t3.c b/arch/arm/mach-tegra/timer-t3.c
index df964fbce154..f23873b214b2 100644
--- a/arch/arm/mach-tegra/timer-t3.c
+++ b/arch/arm/mach-tegra/timer-t3.c
@@ -69,8 +69,13 @@
#define TIMER6_OFFSET (TEGRA_TMR6_BASE-TEGRA_TMR1_BASE)
static void __iomem *timer_reg_base = IO_ADDRESS(TEGRA_TMR1_BASE);
-static cpumask_t wake_timer_ready;
+
+#if defined(CONFIG_PM_SLEEP)
static cpumask_t wake_timer_canceled;
+#if defined(CONFIG_HOTPLUG_CPU)
+static cpumask_t wake_timer_ready;
+#endif
+#endif
#define timer_writel(value, reg) \
__raw_writel(value, (u32)timer_reg_base + (reg))
diff --git a/arch/arm/mach-tegra/usb_phy.c b/arch/arm/mach-tegra/usb_phy.c
index c204aa3b49c2..5940b2f2e1df 100644
--- a/arch/arm/mach-tegra/usb_phy.c
+++ b/arch/arm/mach-tegra/usb_phy.c
@@ -2,7 +2,7 @@
* arch/arm/mach-tegra/usb_phy.c
*
* Copyright (C) 2010 Google, Inc.
- * Copyright (C) 2010 - 2011 NVIDIA Corporation
+ * Copyright (c) 2010-2012, NVIDIA CORPORATION. All rights reserved.
*
* Author:
* Erik Gilling <konkers@google.com>
@@ -18,7 +18,6 @@
* GNU General Public License for more details.
*
*/
-
#include <linux/resource.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -27,582 +26,17 @@
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/gpio.h>
-#include <linux/usb/otg.h>
-#include <linux/usb/ulpi.h>
-#include <asm/mach-types.h>
-#include <mach/usb_phy.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/platform_data/tegra_usb.h>
+#include "tegra_usb_phy.h"
#include <mach/iomap.h>
-#include <mach/pinmux.h>
#include "fuse.h"
-#include "gpio-names.h"
-
-
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
-#define USB_USBCMD 0x140
-#define USB_USBCMD_RS (1 << 0)
-
-#define USB_USBSTS 0x144
-#define USB_USBSTS_PCI (1 << 2)
-#define USB_USBSTS_HCH (1 << 12)
-
-#define USB_TXFILLTUNING 0x164
-#define USB_FIFO_TXFILL_THRES(x) (((x) & 0x1f) << 16)
-#define USB_FIFO_TXFILL_MASK 0x1f0000
-
-#define ULPI_VIEWPORT 0x170
-#define ULPI_WAKEUP (1 << 31)
-#define ULPI_RUN (1 << 30)
-#define ULPI_RD_WR (1 << 29)
-
-#define USB_PORTSC1 0x184
-#define USB_PORTSC1_PTS(x) (((x) & 0x3) << 30)
-#define USB_PORTSC1_PSPD(x) (((x) & 0x3) << 26)
-#define USB_PORTSC1_PHCD (1 << 23)
-#define USB_PORTSC1_WKOC (1 << 22)
-#define USB_PORTSC1_WKDS (1 << 21)
-#define USB_PORTSC1_WKCN (1 << 20)
-#define USB_PORTSC1_PTC(x) (((x) & 0xf) << 16)
-#define USB_PORTSC1_PP (1 << 12)
-#define USB_PORTSC1_LS(x) (((x) & 0x3) << 10)
-#define USB_PORTSC1_SUSP (1 << 7)
-#define USB_PORTSC1_PE (1 << 2)
-#define USB_PORTSC1_CCS (1 << 0)
-
-#define USB_SUSP_CTRL 0x400
-#define USB_WAKE_ON_CNNT_EN_DEV (1 << 3)
-#define USB_WAKE_ON_DISCON_EN_DEV (1 << 4)
-#define USB_SUSP_CLR (1 << 5)
-#define USB_CLKEN (1 << 6)
-#define USB_PHY_CLK_VALID (1 << 7)
-#define USB_PHY_CLK_VALID_INT_ENB (1 << 9)
-#define UTMIP_RESET (1 << 11)
-#define UHSIC_RESET (1 << 11)
-#define UTMIP_PHY_ENABLE (1 << 12)
-#define UHSIC_PHY_ENABLE (1 << 12)
-#define ULPI_PHY_ENABLE (1 << 13)
-#define USB_SUSP_SET (1 << 14)
-#define USB_WAKEUP_DEBOUNCE_COUNT(x) (((x) & 0x7) << 16)
-
-#define USB_PHY_VBUS_WAKEUP_ID 0x408
-#define VDAT_DET_INT_EN (1 << 16)
-#define VDAT_DET_CHG_DET (1 << 17)
-#define VDAT_DET_STS (1 << 18)
-
-#define USB1_LEGACY_CTRL 0x410
-#define USB1_NO_LEGACY_MODE (1 << 0)
-#define USB1_VBUS_SENSE_CTL_MASK (3 << 1)
-#define USB1_VBUS_SENSE_CTL_VBUS_WAKEUP (0 << 1)
-#define USB1_VBUS_SENSE_CTL_AB_SESS_VLD_OR_VBUS_WAKEUP \
- (1 << 1)
-#define USB1_VBUS_SENSE_CTL_AB_SESS_VLD (2 << 1)
-#define USB1_VBUS_SENSE_CTL_A_SESS_VLD (3 << 1)
-
-
-#define UTMIP_PLL_CFG1 0x804
-#define UTMIP_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0)
-#define UTMIP_PLLU_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 27)
-
-#define UTMIP_XCVR_CFG0 0x808
-#define UTMIP_XCVR_SETUP(x) (((x) & 0xf) << 0)
-#define UTMIP_XCVR_LSRSLEW(x) (((x) & 0x3) << 8)
-#define UTMIP_XCVR_LSFSLEW(x) (((x) & 0x3) << 10)
-#define UTMIP_FORCE_PD_POWERDOWN (1 << 14)
-#define UTMIP_FORCE_PD2_POWERDOWN (1 << 16)
-#define UTMIP_FORCE_PDZI_POWERDOWN (1 << 18)
-#define UTMIP_XCVR_LSBIAS_SEL (1 << 21)
-#define UTMIP_XCVR_SETUP_MSB(x) (((x) & 0x7) << 22)
-#define UTMIP_XCVR_HSSLEW_MSB(x) (((x) & 0x7f) << 25)
-
-#define UTMIP_XCVR_MAX_OFFSET 2
-#define UTMIP_XCVR_SETUP_MAX_VALUE 0x7f
-#define UTMIP_XCVR_SETUP_MIN_VALUE 0
-#define XCVR_SETUP_MSB_CALIB(x) ((x) >> 4)
-
-#define UTMIP_BIAS_CFG0 0x80c
-#define UTMIP_OTGPD (1 << 11)
-#define UTMIP_BIASPD (1 << 10)
-
-#define UTMIP_HSRX_CFG0 0x810
-#define UTMIP_ELASTIC_LIMIT(x) (((x) & 0x1f) << 10)
-#define UTMIP_IDLE_WAIT(x) (((x) & 0x1f) << 15)
-
-#define UTMIP_HSRX_CFG1 0x814
-#define UTMIP_HS_SYNC_START_DLY(x) (((x) & 0x1f) << 1)
-
-#define UTMIP_TX_CFG0 0x820
-#define UTMIP_FS_PREABMLE_J (1 << 19)
-#define UTMIP_HS_DISCON_DISABLE (1 << 8)
-
-#define UTMIP_MISC_CFG1 0x828
-#define UTMIP_PLL_ACTIVE_DLY_COUNT(x) (((x) & 0x1f) << 18)
-#define UTMIP_PLLU_STABLE_COUNT(x) (((x) & 0xfff) << 6)
-
-#define UTMIP_DEBOUNCE_CFG0 0x82c
-#define UTMIP_BIAS_DEBOUNCE_A(x) (((x) & 0xffff) << 0)
-
-#define UTMIP_BAT_CHRG_CFG0 0x830
-#define UTMIP_PD_CHRG (1 << 0)
-#define UTMIP_ON_SINK_EN (1 << 2)
-#define UTMIP_OP_SRC_EN (1 << 3)
-
-#define UTMIP_XCVR_CFG1 0x838
-#define UTMIP_FORCE_PDDISC_POWERDOWN (1 << 0)
-#define UTMIP_FORCE_PDCHRP_POWERDOWN (1 << 2)
-#define UTMIP_FORCE_PDDR_POWERDOWN (1 << 4)
-#define UTMIP_XCVR_TERM_RANGE_ADJ(x) (((x) & 0xf) << 18)
-
-#define UTMIP_BIAS_CFG1 0x83c
-#define UTMIP_BIAS_PDTRK_COUNT(x) (((x) & 0x1f) << 3)
-
-#define UHSIC_PLL_CFG1 0x804
-#define UHSIC_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0)
-#define UHSIC_PLLU_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 14)
-
-#define UHSIC_HSRX_CFG0 0x808
-#define UHSIC_ELASTIC_UNDERRUN_LIMIT(x) (((x) & 0x1f) << 2)
-#define UHSIC_ELASTIC_OVERRUN_LIMIT(x) (((x) & 0x1f) << 8)
-#define UHSIC_IDLE_WAIT(x) (((x) & 0x1f) << 13)
-
-#define UHSIC_HSRX_CFG1 0x80c
-#define UHSIC_HS_SYNC_START_DLY(x) (((x) & 0x1f) << 1)
-
-#define UHSIC_TX_CFG0 0x810
-#define UHSIC_HS_POSTAMBLE_OUTPUT_ENABLE (1 << 6)
-
-#define UHSIC_MISC_CFG0 0x814
-#define UHSIC_SUSPEND_EXIT_ON_EDGE (1 << 7)
-#define UHSIC_DETECT_SHORT_CONNECT (1 << 8)
-#define UHSIC_FORCE_XCVR_MODE (1 << 15)
-
-#define UHSIC_MISC_CFG1 0X818
-#define UHSIC_PLLU_STABLE_COUNT(x) (((x) & 0xfff) << 2)
-
-#define UHSIC_PADS_CFG0 0x81c
-#define UHSIC_TX_RTUNEN 0xf000
-#define UHSIC_TX_RTUNE(x) (((x) & 0xf) << 12)
-
-#define UHSIC_PADS_CFG1 0x820
-#define UHSIC_PD_BG (1 << 2)
-#define UHSIC_PD_TX (1 << 3)
-#define UHSIC_PD_TRK (1 << 4)
-#define UHSIC_PD_RX (1 << 5)
-#define UHSIC_PD_ZI (1 << 6)
-#define UHSIC_RX_SEL (1 << 7)
-#define UHSIC_RPD_DATA (1 << 9)
-#define UHSIC_RPD_STROBE (1 << 10)
-#define UHSIC_RPU_DATA (1 << 11)
-#define UHSIC_RPU_STROBE (1 << 12)
-
-#define UHSIC_STAT_CFG0 0x828
-#define UHSIC_CONNECT_DETECT (1 << 0)
-
-
-#else
-#define USB_USBCMD 0x130
-#define USB_USBCMD_RS (1 << 0)
-
-#define USB_USBSTS 0x134
-#define USB_USBSTS_PCI (1 << 2)
-#define USB_USBSTS_SRI (1 << 7)
-#define USB_USBSTS_HCH (1 << 12)
-
-#define USB_TXFILLTUNING 0x154
-#define USB_FIFO_TXFILL_THRES(x) (((x) & 0x1f) << 16)
-#define USB_FIFO_TXFILL_MASK 0x1f0000
-
-#define ULPI_VIEWPORT 0x160
-
-#define USB_PORTSC1 0x174
-#define USB_PORTSC1_WKOC (1 << 22)
-#define USB_PORTSC1_WKDS (1 << 21)
-#define USB_PORTSC1_WKCN (1 << 20)
-#define USB_PORTSC1_PTC(x) (((x) & 0xf) << 16)
-#define USB_PORTSC1_PP (1 << 12)
-#define USB_PORTSC1_LS(x) (((x) & 0x3) << 10)
-#define USB_PORTSC1_SUSP (1 << 7)
-#define USB_PORTSC1_RESUME (1 << 6)
-#define USB_PORTSC1_PE (1 << 2)
-#define USB_PORTSC1_CCS (1 << 0)
-
-#define USB_SUSP_CTRL 0x400
-#define USB_WAKE_ON_CNNT_EN_DEV (1 << 3)
-#define USB_WAKE_ON_DISCON_EN_DEV (1 << 4)
-#define USB_SUSP_CLR (1 << 5)
-#define USB_PHY_CLK_VALID (1 << 7)
-#define USB_PHY_CLK_VALID_INT_ENB (1 << 9)
-
-
-#define UTMIP_RESET (1 << 11)
-#define UTMIP_PHY_ENABLE (1 << 12)
-#define ULPI_PHY_ENABLE (1 << 13)
-#define UHSIC_RESET (1 << 14)
-
-#define USB_WAKEUP_DEBOUNCE_COUNT(x) (((x) & 0x7) << 16)
-#define UHSIC_PHY_ENABLE (1 << 19)
-#define ULPIS2S_SLV0_RESET (1 << 20)
-#define ULPIS2S_SLV1_RESET (1 << 21)
-#define ULPIS2S_LINE_RESET (1 << 22)
-#define ULPI_PADS_RESET (1 << 23)
-#define ULPI_PADS_CLKEN_RESET (1 << 24)
-
-#define USB_PHY_VBUS_WAKEUP_ID 0x408
-#define VDAT_DET_INT_EN (1 << 16)
-#define VDAT_DET_CHG_DET (1 << 17)
-#define VDAT_DET_STS (1 << 18)
-
-#define USB1_LEGACY_CTRL 0x410
-#define USB1_NO_LEGACY_MODE (1 << 0)
-#define USB1_VBUS_SENSE_CTL_MASK (3 << 1)
-#define USB1_VBUS_SENSE_CTL_VBUS_WAKEUP (0 << 1)
-#define USB1_VBUS_SENSE_CTL_AB_SESS_VLD_OR_VBUS_WAKEUP \
- (1 << 1)
-#define USB1_VBUS_SENSE_CTL_AB_SESS_VLD (2 << 1)
-#define USB1_VBUS_SENSE_CTL_A_SESS_VLD (3 << 1)
-
-#define UTMIP_PLL_CFG1 0x804
-#define UTMIP_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0)
-#define UTMIP_PLLU_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 27)
-
-#define UTMIP_XCVR_CFG0 0x808
-#define UTMIP_XCVR_SETUP(x) (((x) & 0xf) << 0)
-#define UTMIP_XCVR_LSRSLEW(x) (((x) & 0x3) << 8)
-#define UTMIP_XCVR_LSFSLEW(x) (((x) & 0x3) << 10)
-#define UTMIP_FORCE_PD_POWERDOWN (1 << 14)
-#define UTMIP_FORCE_PD2_POWERDOWN (1 << 16)
-#define UTMIP_FORCE_PDZI_POWERDOWN (1 << 18)
-#define UTMIP_XCVR_LSBIAS_SEL (1 << 21)
-#define UTMIP_XCVR_SETUP_MSB(x) (((x) & 0x7) << 22)
-#define UTMIP_XCVR_HSSLEW_MSB(x) (((x) & 0x7f) << 25)
-
-#define UTMIP_XCVR_MAX_OFFSET 2
-#define UTMIP_XCVR_SETUP_MAX_VALUE 0x7f
-#define UTMIP_XCVR_SETUP_MIN_VALUE 0
-#define XCVR_SETUP_MSB_CALIB(x) ((x) >> 4)
-
-#define UTMIP_BIAS_CFG0 0x80c
-#define UTMIP_OTGPD (1 << 11)
-#define UTMIP_BIASPD (1 << 10)
-#define UTMIP_HSSQUELCH_LEVEL(x) (((x) & 0x3) << 0)
-#define UTMIP_HSDISCON_LEVEL(x) (((x) & 0x3) << 2)
-#define UTMIP_HSDISCON_LEVEL_MSB (1 << 24)
-
-#define UTMIP_HSRX_CFG0 0x810
-#define UTMIP_ELASTIC_LIMIT(x) (((x) & 0x1f) << 10)
-#define UTMIP_IDLE_WAIT(x) (((x) & 0x1f) << 15)
-
-#define UTMIP_HSRX_CFG1 0x814
-#define UTMIP_HS_SYNC_START_DLY(x) (((x) & 0x1f) << 1)
-
-#define UTMIP_TX_CFG0 0x820
-#define UTMIP_FS_PREABMLE_J (1 << 19)
-#define UTMIP_HS_DISCON_DISABLE (1 << 8)
-
-#define UTMIP_MISC_CFG1 0x828
-#define UTMIP_PLL_ACTIVE_DLY_COUNT(x) (((x) & 0x1f) << 18)
-#define UTMIP_PLLU_STABLE_COUNT(x) (((x) & 0xfff) << 6)
-
-#define UTMIP_DEBOUNCE_CFG0 0x82c
-#define UTMIP_BIAS_DEBOUNCE_A(x) (((x) & 0xffff) << 0)
-
-#define UTMIP_BAT_CHRG_CFG0 0x830
-#define UTMIP_PD_CHRG (1 << 0)
-#define UTMIP_ON_SINK_EN (1 << 2)
-#define UTMIP_OP_SRC_EN (1 << 3)
-
-#define UTMIP_XCVR_CFG1 0x838
-#define UTMIP_FORCE_PDDISC_POWERDOWN (1 << 0)
-#define UTMIP_FORCE_PDCHRP_POWERDOWN (1 << 2)
-#define UTMIP_FORCE_PDDR_POWERDOWN (1 << 4)
-#define UTMIP_XCVR_TERM_RANGE_ADJ(x) (((x) & 0xf) << 18)
-
-#define UTMIP_BIAS_CFG1 0x83c
-#define UTMIP_BIAS_PDTRK_COUNT(x) (((x) & 0x1f) << 3)
-#define UTMIP_BIAS_PDTRK_POWERDOWN (1 << 0)
-#define UTMIP_BIAS_PDTRK_POWERUP (1 << 1)
-
-#define HOSTPC1_DEVLC 0x1b4
-#define HOSTPC1_DEVLC_PHCD (1 << 22)
-#define HOSTPC1_DEVLC_PTS(x) (((x) & 0x7) << 29)
-#define HOSTPC1_DEVLC_PTS_MASK 7
-#define HOSTPC1_DEVLC_PTS_HSIC 4
-#define HOSTPC1_DEVLC_STS (1 << 28)
-#define HOSTPC1_DEVLC_PSPD(x) (((x) & 0x3) << 25)
-#define HOSTPC1_DEVLC_PSPD_MASK 3
-#define HOSTPC1_DEVLC_PSPD_HIGH_SPEED 2
-
-#define TEGRA_USB_USBMODE_REG_OFFSET 0x1f8
-#define TEGRA_USB_USBMODE_HOST (3 << 0)
-
-#define TEGRA_PMC_USB_AO 0xf0
-#define TEGRA_PMC_USB_AO_VBUS_WAKEUP_PD_P0 (1 << 2)
-#define TEGRA_PMC_USB_AO_ID_PD_P0 (1 << 3)
-#define TEGRA_PMC_USB_AO_PD_P2 (0xf << 8)
-
-#define ICUSB_CTRL 0x15c
-
-#define UHSIC_PLL_CFG1 0xc04
-#define UHSIC_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0)
-#define UHSIC_PLLU_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 14)
-
-#define UHSIC_HSRX_CFG0 0xc08
-#define UHSIC_ELASTIC_UNDERRUN_LIMIT(x) (((x) & 0x1f) << 2)
-#define UHSIC_ELASTIC_OVERRUN_LIMIT(x) (((x) & 0x1f) << 8)
-#define UHSIC_IDLE_WAIT(x) (((x) & 0x1f) << 13)
-
-#define UHSIC_HSRX_CFG1 0xc0c
-#define UHSIC_HS_SYNC_START_DLY(x) (((x) & 0x1f) << 1)
-
-#define UHSIC_TX_CFG0 0xc10
-#define UHSIC_HS_READY_WAIT_FOR_VALID (1 << 9)
-
-#define UHSIC_MISC_CFG0 0xc14
-#define UHSIC_SUSPEND_EXIT_ON_EDGE (1 << 7)
-#define UHSIC_DETECT_SHORT_CONNECT (1 << 8)
-#define UHSIC_FORCE_XCVR_MODE (1 << 15)
-#define UHSIC_DISABLE_BUSRESET (1 << 20)
-
-#define UHSIC_MISC_CFG1 0xc18
-#define UHSIC_PLLU_STABLE_COUNT(x) (((x) & 0xfff) << 2)
-
-#define UHSIC_PADS_CFG0 0xc1c
-#define UHSIC_TX_RTUNEN 0xf000
-#define UHSIC_TX_RTUNE(x) (((x) & 0xf) << 12)
-
-#define UHSIC_PADS_CFG1 0xc20
-#define UHSIC_PD_BG (1 << 2)
-#define UHSIC_PD_TX (1 << 3)
-#define UHSIC_PD_TRK (1 << 4)
-#define UHSIC_PD_RX (1 << 5)
-#define UHSIC_PD_ZI (1 << 6)
-#define UHSIC_RX_SEL (1 << 7)
-#define UHSIC_RPD_DATA (1 << 9)
-#define UHSIC_RPD_STROBE (1 << 10)
-#define UHSIC_RPU_DATA (1 << 11)
-#define UHSIC_RPU_STROBE (1 << 12)
-
-#define UHSIC_STAT_CFG0 0xc28
-#define UHSIC_CONNECT_DETECT (1 << 0)
-
-#define PMC_UTMIP_MASTER_CONFIG 0x310
-#define UTMIP_PWR(inst) (1 << (inst))
-
-#define PMC_USB_DEBOUNCE 0xec
-#define UTMIP_LINE_DEB_CNT(x) (((x) & 0xf) << 16)
-
-#define PMC_UTMIP_UHSIC_FAKE 0x218
-#define USBON_VAL(inst) (1 << ((4*(inst))+1))
-#define USBON_VAL_P2 (1 << 9)
-#define USBON_VAL_P1 (1 << 5)
-#define USBON_VAL_P0 (1 << 1)
-#define USBOP_VAL(inst) (1 << (4*(inst)))
-#define USBOP_VAL_P2 (1 << 8)
-#define USBOP_VAL_P1 (1 << 4)
-#define USBOP_VAL_P0 (1 << 0)
-
-#define PMC_SLEEPWALK_CFG 0x200
-#define UTMIP_LINEVAL_WALK_EN(inst) (1 << ((8*(inst))+7))
-#define UTMIP_LINEVAL_WALK_EN_P2 (1 << 23)
-#define UTMIP_LINEVAL_WALK_EN_P1 (1 << 15)
-#define UTMIP_LINEVAL_WALK_EN_P0 (1 << 7)
-#define UTMIP_WAKE_VAL(inst, x) (((x) & 0xf) << ((8*(inst))+4))
-#define UTMIP_WAKE_VAL_P2(x) (((x) & 0xf) << 20)
-#define UTMIP_WAKE_VAL_P1(x) (((x) & 0xf) << 12)
-#define UTMIP_WAKE_VAL_P0(x) (((x) & 0xf) << 4)
-#define WAKE_VAL_NONE 0xc
-#define WAKE_VAL_FSJ 0x2
-#define WAKE_VAL_FSK 0x1
-#define WAKE_VAL_SE0 0x0
-#define WAKE_VAL_ANY 0xf
-
-#define PMC_SLEEP_CFG 0x1fc
-#define UTMIP_TCTRL_USE_PMC(inst) (1 << ((8*(inst))+3))
-#define UTMIP_TCTRL_USE_PMC_P2 (1 << 19)
-#define UTMIP_TCTRL_USE_PMC_P1 (1 << 11)
-#define UTMIP_TCTRL_USE_PMC_P0 (1 << 3)
-#define UTMIP_RCTRL_USE_PMC(inst) (1 << ((8*(inst))+2))
-#define UTMIP_RCTRL_USE_PMC_P2 (1 << 18)
-#define UTMIP_RCTRL_USE_PMC_P1 (1 << 10)
-#define UTMIP_RCTRL_USE_PMC_P0 (1 << 2)
-#define UTMIP_FSLS_USE_PMC(inst) (1 << ((8*(inst))+1))
-#define UTMIP_FSLS_USE_PMC_P2 (1 << 17)
-#define UTMIP_FSLS_USE_PMC_P1 (1 << 9)
-#define UTMIP_FSLS_USE_PMC_P0 (1 << 1)
-#define UTMIP_MASTER_ENABLE(inst) (1 << (8*(inst)))
-#define UTMIP_MASTER_ENABLE_P2 (1 << 16)
-#define UTMIP_MASTER_ENABLE_P1 (1 << 8)
-#define UTMIP_MASTER_ENABLE_P0 (1 << 0)
-#define UHSIC_MASTER_ENABLE_P0 (1 << 24)
-#define UHSIC_WAKE_VAL_P0(x) (((x) & 0xf) << 28)
-
-#define PMC_USB_AO 0xf0
-#define PMC_POWER_DOWN_MASK 0xffff
-#define HSIC_RESERVED_P0 (3 << 14)
-#define HSIC_STOBE_VAL_PD_P0 (1 << 13)
-#define HSIC_DATA_VAL_PD_P0 (1 << 12)
-#define USB_ID_PD(inst) (1 << ((4*(inst))+3))
-#define VBUS_WAKEUP_PD(inst) (1 << ((4*(inst))+2))
-#define USBON_VAL_PD(inst) (1 << ((4*(inst))+1))
-#define USBON_VAL_PD_P2 (1 << 9)
-#define USBON_VAL_PD_P1 (1 << 5)
-#define USBON_VAL_PD_P0 (1 << 1)
-#define USBOP_VAL_PD(inst) (1 << (4*(inst)))
-#define USBOP_VAL_PD_P2 (1 << 8)
-#define USBOP_VAL_PD_P1 (1 << 4)
-#define USBOP_VAL_PD_P0 (1 << 0)
-
-#define PMC_TRIGGERS 0x1ec
-#define UTMIP_CLR_WALK_PTR(inst) (1 << (inst))
-#define UTMIP_CLR_WALK_PTR_P2 (1 << 2)
-#define UTMIP_CLR_WALK_PTR_P1 (1 << 1)
-#define UTMIP_CLR_WALK_PTR_P0 (1 << 0)
-#define UTMIP_CAP_CFG(inst) (1 << ((inst)+4))
-#define UTMIP_CAP_CFG_P2 (1 << 6)
-#define UTMIP_CAP_CFG_P1 (1 << 5)
-#define UTMIP_CAP_CFG_P0 (1 << 4)
-#define UTMIP_CLR_WAKE_ALARM(inst) (1 << ((inst)+12))
-#define UTMIP_CLR_WAKE_ALARM_P2 (1 << 14)
-
-#define PMC_PAD_CFG (0x1f4)
-
-#define PMC_UTMIP_BIAS_MASTER_CNTRL 0x30c
-#define BIAS_MASTER_PROG_VAL (1 << 1)
-
-#define PMC_SLEEPWALK_REG(inst) (0x204 + (4*(inst)))
-#define PMC_SLEEPWALK_P0 0x204
-#define PMC_SLEEPWALK_P1 0x208
-#define PMC_SLEEPWALK_P2 0x20c
-#define UTMIP_USBOP_RPD_A (1 << 0)
-#define UTMIP_USBON_RPD_A (1 << 1)
-#define UTMIP_AP_A (1 << 4)
-#define UTMIP_AN_A (1 << 5)
-#define UTMIP_HIGHZ_A (1 << 6)
-#define UTMIP_USBOP_RPD_B (1 << 8)
-#define UTMIP_USBON_RPD_B (1 << 9)
-#define UTMIP_AP_B (1 << 12)
-#define UTMIP_AN_B (1 << 13)
-#define UTMIP_HIGHZ_B (1 << 14)
-#define UTMIP_USBOP_RPD_C (1 << 16)
-#define UTMIP_USBON_RPD_C (1 << 17)
-#define UTMIP_AP_C (1 << 20)
-#define UTMIP_AN_C (1 << 21)
-#define UTMIP_HIGHZ_C (1 << 22)
-#define UTMIP_USBOP_RPD_D (1 << 24)
-#define UTMIP_USBON_RPD_D (1 << 25)
-#define UTMIP_AP_D (1 << 28)
-#define UTMIP_AN_D (1 << 29)
-#define UTMIP_HIGHZ_D (1 << 30)
-
-#define UTMIP_PMC_WAKEUP0 0x84c
-#define EVENT_INT_ENB (1 << 0)
-
-#define UTMIP_UHSIC_STATUS 0x214
-#define UTMIP_WALK_PTR_VAL(inst) (0x3 << ((inst)*2))
-#define UTMIP_USBOP_VAL(inst) (1 << ((2*(inst)) + 8))
-#define UTMIP_USBOP_VAL_P2 (1 << 12)
-#define UTMIP_USBOP_VAL_P1 (1 << 10)
-#define UTMIP_USBOP_VAL_P0 (1 << 8)
-#define UTMIP_USBON_VAL(inst) (1 << ((2*(inst)) + 9))
-#define UTMIP_USBON_VAL_P2 (1 << 13)
-#define UTMIP_USBON_VAL_P1 (1 << 11)
-#define UTMIP_USBON_VAL_P0 (1 << 9)
-#define UTMIP_WAKE_ALARM(inst) (1 << ((inst) + 16))
-#define UTMIP_WAKE_ALARM_P2 (1 << 18)
-#define UTMIP_WAKE_ALARM_P1 (1 << 17)
-#define UTMIP_WAKE_ALARM_P0 (1 << 16)
-#define UTMIP_WALK_PTR(inst) (1 << ((inst)*2))
-#define UTMIP_WALK_PTR_P2 (1 << 4)
-#define UTMIP_WALK_PTR_P1 (1 << 2)
-#define UTMIP_WALK_PTR_P0 (1 << 0)
-
-#define UTMIP_BIAS_STS0 0x840
-#define UTMIP_RCTRL_VAL(x) (((x) & 0xffff) << 0)
-#define UTMIP_TCTRL_VAL(x) (((x) & (0xffff << 16)) >> 16)
-
-#define PMC_UTMIP_TERM_PAD_CFG 0x1f8
-#define PMC_TCTRL_VAL(x) (((x) & 0x1f) << 5)
-#define PMC_RCTRL_VAL(x) (((x) & 0x1f) << 0)
-
-#define UHSIC_SLEEPWALK_REG 0x210
-#define UHSIC_DATA_RPD_D (1 << 25)
-#define UHSIC_STRB_RPD_D (1 << 24)
-#define UHSIC_DATA_RPD_C (1 << 17)
-#define UHSIC_STRB_RPD_C (1 << 16)
-#define UHSIC_DATA_RPD_B (1 << 9)
-#define UHSIC_STRB_RPD_B (1 << 8)
-#define UHSIC_DATA_RPD_A (1 << 1)
-#define UHSIC_STRB_RPD_A (1 << 0)
-
-static u32 utmip_rctrl_val, utmip_tctrl_val;
-
-#endif
-
-/* Common registers */
-#define UTMIP_MISC_CFG0 0x824
-#define UTMIP_DPDM_OBSERVE (1 << 26)
-#define UTMIP_DPDM_OBSERVE_SEL(x) (((x) & 0xf) << 27)
-#define UTMIP_DPDM_OBSERVE_SEL_FS_J UTMIP_DPDM_OBSERVE_SEL(0xf)
-#define UTMIP_DPDM_OBSERVE_SEL_FS_K UTMIP_DPDM_OBSERVE_SEL(0xe)
-#define UTMIP_DPDM_OBSERVE_SEL_FS_SE1 UTMIP_DPDM_OBSERVE_SEL(0xd)
-#define UTMIP_DPDM_OBSERVE_SEL_FS_SE0 UTMIP_DPDM_OBSERVE_SEL(0xc)
-#define UTMIP_SUSPEND_EXIT_ON_EDGE (1 << 22)
-#define FORCE_PULLDN_DM (1 << 8)
-#define FORCE_PULLDN_DP (1 << 9)
-#define COMB_TERMS (1 << 0)
-#define ALWAYS_FREE_RUNNING_TERMS (1 << 1)
-
-#define ULPIS2S_CTRL 0x418
-#define ULPIS2S_ENA (1 << 0)
-#define ULPIS2S_SUPPORT_DISCONNECT (1 << 2)
-#define ULPIS2S_PLLU_MASTER_BLASTER60 (1 << 3)
-#define ULPIS2S_SPARE(x) (((x) & 0xF) << 8)
-#define ULPIS2S_FORCE_ULPI_CLK_OUT (1 << 12)
-#define ULPIS2S_DISCON_DONT_CHECK_SE0 (1 << 13)
-#define ULPIS2S_SUPPORT_HS_KEEP_ALIVE (1 << 14)
-#define ULPIS2S_DISABLE_STP_PU (1 << 15)
-#define ULPIS2S_SLV0_CLAMP_XMIT (1 << 16)
-
-
-#define ULPI_TIMING_CTRL_0 0x424
-#define ULPI_CLOCK_OUT_DELAY(x) ((x) & 0x1F)
-#define ULPI_OUTPUT_PINMUX_BYP (1 << 10)
-#define ULPI_CLKOUT_PINMUX_BYP (1 << 11)
-#define ULPI_SHADOW_CLK_LOOPBACK_EN (1 << 12)
-#define ULPI_SHADOW_CLK_SEL (1 << 13)
-#define ULPI_CORE_CLK_SEL (1 << 14)
-#define ULPI_SHADOW_CLK_DELAY(x) (((x) & 0x1F) << 16)
-#define ULPI_LBK_PAD_EN (1 << 26)
-#define ULPI_LBK_PAD_E_INPUT_OR (1 << 27)
-#define ULPI_CLK_OUT_ENA (1 << 28)
-#define ULPI_CLK_PADOUT_ENA (1 << 29)
-
-#define ULPI_TIMING_CTRL_1 0x428
-#define ULPI_DATA_TRIMMER_LOAD (1 << 0)
-#define ULPI_DATA_TRIMMER_SEL(x) (((x) & 0x7) << 1)
-#define ULPI_STPDIRNXT_TRIMMER_LOAD (1 << 16)
-#define ULPI_STPDIRNXT_TRIMMER_SEL(x) (((x) & 0x7) << 17)
-#define ULPI_DIR_TRIMMER_LOAD (1 << 24)
-#define ULPI_DIR_TRIMMER_SEL(x) (((x) & 0x7) << 25)
-
-#define UTMIP_SPARE_CFG0 0x834
-#define FUSE_SETUP_SEL (1 << 3)
-#define FUSE_ATERM_SEL (1 << 4)
-
-#define FUSE_USB_CALIB_0 0x1F0
-#define FUSE_USB_CALIB_XCVR_SETUP(x) (((x) & 0x7F) << 0)
-
-#define UHSIC_PLL_CFG0 0x800
-
-#define UHSIC_CMD_CFG0 0x824
-#define UHSIC_PRETEND_CONNECT_DETECT (1 << 5)
-
-#define UHSIC_SPARE_CFG0 0x82c
-
-/* These values (in milli second) are taken from the battery charging spec */
-#define TDP_SRC_ON_MS 100
-#define TDPSRC_CON_MS 40
-
-#define CONNECT_DETECT_TIMEOUT 25000
+#define ERR(stuff...) pr_err("usb_phy: " stuff)
+#define WARNING(stuff...) pr_warning("usb_phy: " stuff)
+#define INFO(stuff...) pr_info("usb_phy: " stuff)
#define AHB_MEM_PREFETCH_CFG3 0xe0
#define AHB_MEM_PREFETCH_CFG4 0xe4
@@ -610,2615 +44,654 @@ static u32 utmip_rctrl_val, utmip_tctrl_val;
#define AHB_MEM_PREFETCH_CFG2 0xf0
#define PREFETCH_ENB (1 << 31)
-static DEFINE_SPINLOCK(utmip_pad_lock);
-static int utmip_pad_count;
-
-struct tegra_xtal_freq {
- int freq;
- u8 enable_delay;
- u8 stable_count;
- u8 active_delay;
- u16 xtal_freq_count;
- u16 debounce;
- u8 pdtrk_count;
-};
-
-static const struct tegra_xtal_freq tegra_freq_table[] = {
- {
- .freq = 12000000,
- .enable_delay = 0x02,
- .stable_count = 0x2F,
- .active_delay = 0x04,
- .xtal_freq_count = 0x76,
- .debounce = 0x7530,
- .pdtrk_count = 5,
- },
- {
- .freq = 13000000,
- .enable_delay = 0x02,
- .stable_count = 0x33,
- .active_delay = 0x05,
- .xtal_freq_count = 0x7F,
- .debounce = 0x7EF4,
- .pdtrk_count = 5,
- },
- {
- .freq = 19200000,
- .enable_delay = 0x03,
- .stable_count = 0x4B,
- .active_delay = 0x06,
- .xtal_freq_count = 0xBB,
- .debounce = 0xBB80,
- .pdtrk_count = 7,
- },
- {
- .freq = 26000000,
- .enable_delay = 0x04,
- .stable_count = 0x66,
- .active_delay = 0x09,
- .xtal_freq_count = 0xFE,
- .debounce = 0xFDE8,
- .pdtrk_count = 9,
- },
-};
-
-static const struct tegra_xtal_freq tegra_uhsic_freq_table[] = {
- {
- .freq = 12000000,
- .enable_delay = 0x02,
- .stable_count = 0x2F,
- .active_delay = 0x0,
- .xtal_freq_count = 0x1CA,
- },
- {
- .freq = 13000000,
- .enable_delay = 0x02,
- .stable_count = 0x33,
- .active_delay = 0x0,
- .xtal_freq_count = 0x1F0,
- },
- {
- .freq = 19200000,
- .enable_delay = 0x03,
- .stable_count = 0x4B,
- .active_delay = 0x0,
- .xtal_freq_count = 0x2DD,
- },
- {
- .freq = 26000000,
- .enable_delay = 0x04,
- .stable_count = 0x66,
- .active_delay = 0x0,
- .xtal_freq_count = 0x3E0,
- },
-};
-
-static struct tegra_utmip_config utmip_default[] = {
- [0] = {
- .hssync_start_delay = 9,
- .idle_wait_delay = 17,
- .elastic_limit = 16,
- .term_range_adj = 6,
- .xcvr_setup = 9,
- .xcvr_setup_offset = 0,
- .xcvr_use_fuses = 1,
- .xcvr_lsfslew = 2,
- .xcvr_lsrslew = 2,
- },
- [2] = {
- .hssync_start_delay = 9,
- .idle_wait_delay = 17,
- .elastic_limit = 16,
- .term_range_adj = 6,
- .xcvr_setup_offset = 0,
- .xcvr_use_fuses = 1,
- .xcvr_setup = 9,
- .xcvr_lsfslew = 2,
- .xcvr_lsrslew = 2,
- },
-};
-
-struct usb_phy_plat_data usb_phy_data[] = {
- { 0, 0, -1, (int)NULL},
- { 0, 0, -1, (int)NULL},
- { 0, 0, -1, (int)NULL},
-};
-
-static int utmip_pad_open(struct tegra_usb_phy *phy)
+#ifdef DEBUG
+#define DBG(stuff...) pr_info("usb_phy: " stuff)
+#else
+#define DBG(stuff...) do {} while (0)
+#endif
+
+static void print_usb_plat_data_info(struct tegra_usb_phy *phy)
{
- phy->pad_clk = clk_get_sys("utmip-pad", NULL);
- if (IS_ERR(phy->pad_clk)) {
- pr_err("%s: can't get utmip pad clock\n", __func__);
- return PTR_ERR(phy->pad_clk);
- }
+ struct tegra_usb_platform_data *pdata = phy->pdata;
+ char op_mode[][50] = {
+ "TEGRA_USB_OPMODE_DEVICE",
+ "TEGRA_USB_OPMODE_HOST"
+ };
+ char phy_intf[][50] = {
+ "USB_PHY_INTF_UTMI",
+ "USB_PHY_INTF_ULPI_LINK",
+ "USB_PHY_INTF_ULPI_NULL",
+ "USB_PHY_INTF_HSIC",
+ "USB_PHY_INTF_ICUSB"
+ };
- if (phy->instance == 0) {
- phy->pad_regs = phy->regs;
+ pr_info("tegra USB phy - inst[%d] platform info:\n", phy->inst);
+ pr_info("port_otg: %s\n", pdata->port_otg ? "yes" : "no");
+ pr_info("has_hostpc: %s\n", pdata->has_hostpc ? "yes" : "no");
+ pr_info("phy_interface: %s\n", phy_intf[pdata->phy_intf]);
+ pr_info("op_mode: %s\n", op_mode[pdata->op_mode]);
+ if (pdata->op_mode == TEGRA_USB_OPMODE_DEVICE) {
+ pr_info("vbus_pmu_irq: %d\n", pdata->u_data.dev.vbus_pmu_irq);
+ pr_info("vbus_gpio: %d\n", pdata->u_data.dev.vbus_gpio);
+ pr_info("charging: %s\n", pdata->u_data.dev.charging_supported ?
+ "enabled" : "disabled");
+ pr_info("remote_wakeup: %s\n", pdata->u_data.dev.remote_wakeup_supported
+ ? "enabled" : "disabled");
} else {
- phy->pad_regs = ioremap(TEGRA_USB_BASE, TEGRA_USB_SIZE);
- if (!phy->pad_regs) {
- pr_err("%s: can't remap usb registers\n", __func__);
- clk_put(phy->pad_clk);
- return -ENOMEM;
- }
+ pr_info("vbus_gpio: %d\n", pdata->u_data.host.vbus_gpio);
+ pr_info("vbus_gpio_inverted: %d\n", pdata->u_data.host.vbus_gpio_inverted);
+ pr_info("vbus_reg: %s\n", pdata->u_data.host.vbus_reg ?
+ pdata->u_data.host.vbus_reg : "NULL");
+ pr_info("hot_plug: %s\n", pdata->u_data.host.hot_plug ?
+ "enabled" : "disabled");
+ pr_info("remote_wakeup: %s\n", pdata->u_data.host.remote_wakeup_supported
+ ? "enabled" : "disabled");
}
- return 0;
-}
-
-static void utmip_pad_close(struct tegra_usb_phy *phy)
-{
- if (phy->instance != 0)
- iounmap(phy->pad_regs);
- clk_put(phy->pad_clk);
}
-static int utmip_pad_power_on(struct tegra_usb_phy *phy)
+static void usb_host_vbus_enable(struct tegra_usb_phy *phy, bool enable)
{
- unsigned long val, flags;
- void __iomem *base = phy->pad_regs;
-
- clk_enable(phy->pad_clk);
-
- spin_lock_irqsave(&utmip_pad_lock, flags);
-
- utmip_pad_count++;
- val = readl(base + UTMIP_BIAS_CFG0);
- val &= ~(UTMIP_OTGPD | UTMIP_BIASPD);
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- val |= UTMIP_HSSQUELCH_LEVEL(0x2) | UTMIP_HSDISCON_LEVEL(0x1) |
- UTMIP_HSDISCON_LEVEL_MSB;
-#endif
- writel(val, base + UTMIP_BIAS_CFG0);
-
- spin_unlock_irqrestore(&utmip_pad_lock, flags);
-
- clk_disable(phy->pad_clk);
-
- return 0;
-}
-
-static int utmip_pad_power_off(struct tegra_usb_phy *phy, bool is_dpd)
-{
- unsigned long val, flags;
- void __iomem *base = phy->pad_regs;
-
- if (!utmip_pad_count) {
- pr_err("%s: utmip pad already powered off\n", __func__);
- return -EINVAL;
- }
-
- clk_enable(phy->pad_clk);
-
- spin_lock_irqsave(&utmip_pad_lock, flags);
-
- if (--utmip_pad_count == 0 && is_dpd) {
- val = readl(base + UTMIP_BIAS_CFG0);
- val |= UTMIP_OTGPD | UTMIP_BIASPD;
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- val &= ~(UTMIP_HSSQUELCH_LEVEL(~0) | UTMIP_HSDISCON_LEVEL(~0) |
- UTMIP_HSDISCON_LEVEL_MSB);
-#endif
- writel(val, base + UTMIP_BIAS_CFG0);
+ if (phy->vbus_reg) {
+ if (enable)
+ regulator_enable(phy->vbus_reg);
+ else
+ regulator_disable(phy->vbus_reg);
+ } else {
+ int gpio = phy->pdata->u_data.host.vbus_gpio;
+ if (gpio == -1)
+ return;
+ gpio_set_value_cansleep(gpio, (enable != phy->pdata->u_data.host.vbus_gpio_inverted)? 1 : 0);
}
-
- spin_unlock_irqrestore(&utmip_pad_lock, flags);
-
- clk_disable(phy->pad_clk);
-
- return 0;
}
-static int utmi_wait_register(void __iomem *reg, u32 mask, u32 result)
+int usb_phy_reg_status_wait(void __iomem *reg, u32 mask,
+ u32 result, u32 timeout)
{
- unsigned long timeout = 2500;
do {
if ((readl(reg) & mask) == result)
return 0;
udelay(1);
timeout--;
} while (timeout);
- return -1;
-}
-static int utmi_wait_register_timeout(void __iomem *reg, u32 mask, u32 result,
- unsigned long timeout)
-{
- do {
- if ((readl(reg) & mask) == result)
- return 0;
- udelay(1);
- timeout--;
- } while (timeout);
return -1;
}
-static void utmi_phy_clk_disable(struct tegra_usb_phy *phy)
+static int tegra_usb_phy_init_ops(struct tegra_usb_phy *phy)
{
- unsigned long val;
- void __iomem *base = phy->regs;
+ int err = 0;
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- if (phy->instance == 0) {
- val = readl(base + USB_SUSP_CTRL);
- val |= USB_SUSP_SET;
- writel(val, base + USB_SUSP_CTRL);
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
- udelay(10);
-
- val = readl(base + USB_SUSP_CTRL);
- val &= ~USB_SUSP_SET;
- writel(val, base + USB_SUSP_CTRL);
- }
-
- if (phy->instance == 2) {
- val = readl(base + USB_PORTSC1);
- val |= USB_PORTSC1_PHCD;
- writel(val, base + USB_PORTSC1);
- }
-#else
- val = readl(base + HOSTPC1_DEVLC);
- val |= HOSTPC1_DEVLC_PHCD;
- writel(val, base + HOSTPC1_DEVLC);
-#endif
- if (phy->hotplug) {
- val = readl(base + USB_SUSP_CTRL);
- val |= USB_PHY_CLK_VALID_INT_ENB;
- writel(val, base + USB_SUSP_CTRL);
- } else {
- val = readl(base + USB_SUSP_CTRL);
- val |= UTMIP_RESET;
- writel(val, base + USB_SUSP_CTRL);
- }
+ if (phy->pdata->has_hostpc)
+ err = tegra3_usb_phy_init_ops(phy);
+ else
+ err = tegra2_usb_phy_init_ops(phy);
- if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, 0) < 0)
- pr_err("%s: timeout waiting for phy to stabilize\n", __func__);
+ return err;
}
-static void utmi_phy_clk_enable(struct tegra_usb_phy *phy)
+static irqreturn_t usb_phy_dev_vbus_pmu_irq_thr(int irq, void *pdata)
{
- unsigned long val;
- void __iomem *base = phy->regs;
-
- if (phy->instance == 0) {
- val = readl(base + USB_SUSP_CTRL);
- val |= USB_SUSP_CLR;
- writel(val, base + USB_SUSP_CTRL);
-
- udelay(10);
+ struct tegra_usb_phy *phy = pdata;
- val = readl(base + USB_SUSP_CTRL);
- val &= ~USB_SUSP_CLR;
- writel(val, base + USB_SUSP_CTRL);
+ if (phy->vdd_reg && !phy->vdd_reg_on) {
+ regulator_enable(phy->vdd_reg);
+ phy->vdd_reg_on = 1;
+ /*
+ * Optimal time to get the regulator turned on
+ * before detecting vbus interrupt.
+ */
+ mdelay(15);
}
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- if (phy->instance == 2) {
- val = readl(base + USB_PORTSC1);
- val &= ~USB_PORTSC1_PHCD;
- writel(val, base + USB_PORTSC1);
+ /* clk is disabled during phy power off and not here*/
+ if (!phy->ctrl_clk_on) {
+ clk_enable(phy->ctrlr_clk);
+ phy->ctrl_clk_on = true;
}
-#endif
-
- if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID,
- USB_PHY_CLK_VALID) < 0)
- pr_err("%s: timeout waiting for phy to stabilize\n", __func__);
-}
-static void vbus_enable(struct tegra_usb_phy *phy)
-{
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- int gpio_status;
- int gpio = usb_phy_data[phy->instance].vbus_gpio;
- int gpio_inverted = usb_phy_data[phy->instance].vbus_gpio_inverted;
-
- if (gpio == -1)
- return;
-
- gpio_status = gpio_request(gpio,"VBUS_USB");
- if (gpio_status < 0) {
- printk("VBUS_USB request GPIO FAILED\n");
- WARN_ON(1);
- return;
- }
- if (gpio < TEGRA_NR_GPIOS) tegra_gpio_enable(gpio);
- gpio_status = gpio_direction_output(gpio, !gpio_inverted);
- if (gpio_status < 0) {
- printk("VBUS_USB request GPIO DIRECTION FAILED \n");
- WARN_ON(1);
- return;
- }
- gpio_set_value_cansleep(gpio, !gpio_inverted);
-#else
- if (phy->reg_vbus)
- regulator_enable(phy->reg_vbus);
-#endif
-}
-
-static void vbus_disable(struct tegra_usb_phy *phy)
-{
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- int gpio = usb_phy_data[phy->instance].vbus_gpio;
- int gpio_inverted = usb_phy_data[phy->instance].vbus_gpio_inverted;
-
- if (gpio == -1)
- return;
-
- gpio_set_value_cansleep(gpio, gpio_inverted);
- gpio_free(gpio);
-#else
- if (phy->reg_vbus)
- regulator_disable(phy->reg_vbus);
-#endif
-}
-
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
-static void utmip_phy_enable_trking_data(struct tegra_usb_phy *phy)
-{
- void __iomem *base = phy->pad_regs;
- void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
- static bool init_done = false;
- u32 val;
-
- /* Should be done only once after system boot */
- if (init_done)
- return;
-
- clk_enable(phy->pad_clk);
- /* Bias pad MASTER_ENABLE=1 */
- val = readl(pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL);
- val |= BIAS_MASTER_PROG_VAL;
- writel(val, pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL);
-
- /* Setting the tracking length time */
- val = readl(base + UTMIP_BIAS_CFG1);
- val &= ~UTMIP_BIAS_PDTRK_COUNT(~0);
- val |= UTMIP_BIAS_PDTRK_COUNT(5);
- writel(val, base + UTMIP_BIAS_CFG1);
-
- /* Bias PDTRK is Shared and MUST be done from USB1 ONLY, PD_TRK=0 */
- val = readl(base + UTMIP_BIAS_CFG1);
- val &= ~ UTMIP_BIAS_PDTRK_POWERDOWN;
- writel(val, base + UTMIP_BIAS_CFG1);
-
- val = readl(base + UTMIP_BIAS_CFG1);
- val |= UTMIP_BIAS_PDTRK_POWERUP;
- writel(val, base + UTMIP_BIAS_CFG1);
-
- /* Wait for 25usec */
- udelay(25);
-
- /* Bias pad MASTER_ENABLE=0 */
- val = readl(pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL);
- val &= ~BIAS_MASTER_PROG_VAL;
- writel(val, pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL);
-
- /* Wait for 1usec */
- udelay(1);
-
- /* Bias pad MASTER_ENABLE=1 */
- val = readl(pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL);
- val |= BIAS_MASTER_PROG_VAL;
- writel(val, pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL);
-
- /* Read RCTRL and TCTRL from UTMIP space */
- val = readl(base + UTMIP_BIAS_STS0);
- utmip_rctrl_val = ffz(UTMIP_RCTRL_VAL(val));
- utmip_tctrl_val = ffz(UTMIP_TCTRL_VAL(val));
-
- /* PD_TRK=1 */
- val = readl(base + UTMIP_BIAS_CFG1);
- val |= UTMIP_BIAS_PDTRK_POWERDOWN;
- writel(val, base + UTMIP_BIAS_CFG1);
-
- /* Program thermally encoded RCTRL_VAL, TCTRL_VAL into PMC space */
- val = readl(pmc_base + PMC_UTMIP_TERM_PAD_CFG);
- val = PMC_TCTRL_VAL(utmip_tctrl_val) | PMC_RCTRL_VAL(utmip_rctrl_val);
- writel(val, pmc_base + PMC_UTMIP_TERM_PAD_CFG);
- clk_disable(phy->pad_clk);
- init_done = true;
-}
-
-static void utmip_powerdown_pmc_wake_detect(struct tegra_usb_phy *phy)
-{
- unsigned long val;
- void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
- unsigned int inst = phy->instance;
-
- /* power down UTMIP interfaces */
- val = readl(pmc_base + PMC_UTMIP_MASTER_CONFIG);
- val |= UTMIP_PWR(inst);
- writel(val, pmc_base + PMC_UTMIP_MASTER_CONFIG);
-
- /* setup sleep walk usb controller */
- val = UTMIP_USBOP_RPD_A | UTMIP_USBON_RPD_A | UTMIP_HIGHZ_A |
- UTMIP_USBOP_RPD_B | UTMIP_USBON_RPD_B | UTMIP_HIGHZ_B |
- UTMIP_USBOP_RPD_C | UTMIP_USBON_RPD_C | UTMIP_HIGHZ_C |
- UTMIP_USBOP_RPD_D | UTMIP_USBON_RPD_D | UTMIP_HIGHZ_D;
- writel(val, pmc_base + PMC_SLEEPWALK_REG(inst));
-
- /* Program thermally encoded RCTRL_VAL, TCTRL_VAL into PMC space */
- val = readl(pmc_base + PMC_UTMIP_TERM_PAD_CFG);
- val = PMC_TCTRL_VAL(utmip_tctrl_val) | PMC_RCTRL_VAL(utmip_rctrl_val);
- writel(val, pmc_base + PMC_UTMIP_TERM_PAD_CFG);
-
- /* Turn over pad configuration to PMC */
- val = readl(pmc_base + PMC_SLEEP_CFG);
- val &= ~UTMIP_WAKE_VAL(inst, ~0);
- val |= UTMIP_WAKE_VAL(inst, WAKE_VAL_NONE) |
- UTMIP_RCTRL_USE_PMC(inst) | UTMIP_TCTRL_USE_PMC(inst) |
- UTMIP_FSLS_USE_PMC(inst) | UTMIP_MASTER_ENABLE(inst);
- writel(val, pmc_base + PMC_SLEEP_CFG);
-}
-
-static void utmip_powerup_pmc_wake_detect(struct tegra_usb_phy *phy)
-{
- unsigned long val;
- void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
- unsigned int inst = phy->instance;
-
- /* Disable PMC master mode by clearing MASTER_EN */
- val = readl(pmc_base + PMC_SLEEP_CFG);
- val &= ~(UTMIP_RCTRL_USE_PMC(inst) | UTMIP_TCTRL_USE_PMC(inst) |
- UTMIP_FSLS_USE_PMC(inst) | UTMIP_MASTER_ENABLE(inst));
- writel(val, pmc_base + PMC_SLEEP_CFG);
- mdelay(1);
-}
-
-static void uhsic_powerdown_pmc_wake_detect(struct tegra_usb_phy *phy)
-{
- unsigned long val;
- void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
-
- /* turn on pad detectors for HSIC*/
- val = readl(pmc_base + PMC_USB_AO);
- val |= (HSIC_RESERVED_P0 | HSIC_STOBE_VAL_PD_P0 | HSIC_DATA_VAL_PD_P0);
- writel(val, pmc_base + PMC_USB_AO);
-
- /* enable pull downs on HSIC PMC */
- val = UHSIC_STRB_RPD_A | UHSIC_DATA_RPD_A | UHSIC_STRB_RPD_B |
- UHSIC_DATA_RPD_B | UHSIC_STRB_RPD_C | UHSIC_DATA_RPD_C |
- UHSIC_STRB_RPD_D | UHSIC_DATA_RPD_D;
- writel(val, pmc_base + UHSIC_SLEEPWALK_REG);
-
- /* Turn over pad configuration to PMC */
- val = readl(pmc_base + PMC_SLEEP_CFG);
- val &= ~UHSIC_WAKE_VAL_P0(~0);
- val |= UHSIC_WAKE_VAL_P0(WAKE_VAL_NONE) | UHSIC_MASTER_ENABLE_P0;
- writel(val, pmc_base + PMC_SLEEP_CFG);
-}
-
-static void uhsic_powerup_pmc_wake_detect(struct tegra_usb_phy *phy)
-{
- unsigned long val;
- void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
-
- /* turn on pad detectors for HSIC*/
- val = readl(pmc_base + PMC_USB_AO);
- val &= ~(HSIC_RESERVED_P0 | HSIC_STOBE_VAL_PD_P0 | HSIC_DATA_VAL_PD_P0);
- writel(val, pmc_base + PMC_USB_AO);
-
- /* Disable PMC master mode by clearing MASTER_EN */
- val = readl(pmc_base + PMC_SLEEP_CFG);
- val &= ~(UHSIC_MASTER_ENABLE_P0);
- writel(val, pmc_base + PMC_SLEEP_CFG);
- mdelay(1);
+ return IRQ_HANDLED;
}
-#endif
-static unsigned int tegra_phy_xcvr_setup_value(struct tegra_utmip_config *cfg)
+static void tegra_usb_phy_release_clocks(struct tegra_usb_phy *phy)
{
- signed long val;
-
- if (cfg->xcvr_use_fuses) {
- val = FUSE_USB_CALIB_XCVR_SETUP(
- tegra_fuse_readl(FUSE_USB_CALIB_0));
- if (cfg->xcvr_setup_offset <= UTMIP_XCVR_MAX_OFFSET)
- val = val + cfg->xcvr_setup_offset;
-
- if (val > UTMIP_XCVR_SETUP_MAX_VALUE) {
- val = UTMIP_XCVR_SETUP_MAX_VALUE;
- pr_info("%s: reset XCVR_SETUP to max value\n",
- __func__);
- } else if (val < UTMIP_XCVR_SETUP_MIN_VALUE) {
- val = UTMIP_XCVR_SETUP_MIN_VALUE;
- pr_info("%s: reset XCVR_SETUP to min value\n",
- __func__);
- }
- } else {
- val = cfg->xcvr_setup;
- }
-
- return (unsigned int)val;
+ clk_put(phy->emc_clk);
+ clk_put(phy->sys_clk);
+ if (phy->pdata->op_mode == TEGRA_USB_OPMODE_HOST)
+ if (phy->pdata->u_data.host.hot_plug ||
+ phy->pdata->u_data.host.remote_wakeup_supported)
+ clk_disable(phy->ctrlr_clk);
+ clk_put(phy->ctrlr_clk);
+ clk_disable(phy->pllu_clk);
+ clk_put(phy->pllu_clk);
}
-static int utmi_phy_power_on(struct tegra_usb_phy *phy, bool is_dpd)
+static int tegra_usb_phy_get_clocks(struct tegra_usb_phy *phy)
{
- unsigned long val;
- void __iomem *base = phy->regs;
- unsigned int xcvr_setup_value;
- struct tegra_utmip_config *config = phy->config;
-
- val = readl(base + USB_SUSP_CTRL);
- val |= UTMIP_RESET;
- writel(val, base + USB_SUSP_CTRL);
-
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- if (phy->instance == 0) {
- val = readl(base + USB1_LEGACY_CTRL);
- val |= USB1_NO_LEGACY_MODE;
- writel(val, base + USB1_LEGACY_CTRL);
- }
-#endif
-
- val = readl(base + UTMIP_TX_CFG0);
- val |= UTMIP_FS_PREABMLE_J;
- writel(val, base + UTMIP_TX_CFG0);
-
- val = readl(base + UTMIP_HSRX_CFG0);
- val &= ~(UTMIP_IDLE_WAIT(~0) | UTMIP_ELASTIC_LIMIT(~0));
- val |= UTMIP_IDLE_WAIT(config->idle_wait_delay);
- val |= UTMIP_ELASTIC_LIMIT(config->elastic_limit);
- writel(val, base + UTMIP_HSRX_CFG0);
-
- val = readl(base + UTMIP_HSRX_CFG1);
- val &= ~UTMIP_HS_SYNC_START_DLY(~0);
- val |= UTMIP_HS_SYNC_START_DLY(config->hssync_start_delay);
- writel(val, base + UTMIP_HSRX_CFG1);
-
- val = readl(base + UTMIP_DEBOUNCE_CFG0);
- val &= ~UTMIP_BIAS_DEBOUNCE_A(~0);
- val |= UTMIP_BIAS_DEBOUNCE_A(phy->freq->debounce);
- writel(val, base + UTMIP_DEBOUNCE_CFG0);
-
- val = readl(base + UTMIP_MISC_CFG0);
- val &= ~UTMIP_SUSPEND_EXIT_ON_EDGE;
- writel(val, base + UTMIP_MISC_CFG0);
-
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- val = readl(base + UTMIP_MISC_CFG1);
- val &= ~(UTMIP_PLL_ACTIVE_DLY_COUNT(~0) | UTMIP_PLLU_STABLE_COUNT(~0));
- val |= UTMIP_PLL_ACTIVE_DLY_COUNT(phy->freq->active_delay) |
- UTMIP_PLLU_STABLE_COUNT(phy->freq->stable_count);
- writel(val, base + UTMIP_MISC_CFG1);
-
- val = readl(base + UTMIP_PLL_CFG1);
- val &= ~(UTMIP_XTAL_FREQ_COUNT(~0) | UTMIP_PLLU_ENABLE_DLY_COUNT(~0));
- val |= UTMIP_XTAL_FREQ_COUNT(phy->freq->xtal_freq_count) |
- UTMIP_PLLU_ENABLE_DLY_COUNT(phy->freq->enable_delay);
- writel(val, base + UTMIP_PLL_CFG1);
-#endif
+ int err = 0;
- if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) {
- val = readl(base + USB_SUSP_CTRL);
- val &= ~(USB_WAKE_ON_CNNT_EN_DEV | USB_WAKE_ON_DISCON_EN_DEV);
- writel(val, base + USB_SUSP_CTRL);
+ phy->pllu_clk = clk_get_sys(NULL, "pll_u");
+ if (IS_ERR(phy->pllu_clk)) {
+ ERR("inst:[%d] Can't get pllu_clk clock\n", phy->inst);
+ err = PTR_ERR(phy->pllu_clk);
+ goto fail_pll;
}
+ clk_enable(phy->pllu_clk);
- utmip_pad_power_on(phy);
-
- xcvr_setup_value = phy->xcvr_setup_value;
-
- val = readl(base + UTMIP_XCVR_CFG0);
- val &= ~(UTMIP_XCVR_LSBIAS_SEL | UTMIP_FORCE_PD_POWERDOWN |
- UTMIP_FORCE_PD2_POWERDOWN | UTMIP_FORCE_PDZI_POWERDOWN |
- UTMIP_XCVR_SETUP(~0) | UTMIP_XCVR_LSFSLEW(~0) |
- UTMIP_XCVR_LSRSLEW(~0) | UTMIP_XCVR_HSSLEW_MSB(~0));
- val |= UTMIP_XCVR_SETUP(xcvr_setup_value);
- val |= UTMIP_XCVR_SETUP_MSB(XCVR_SETUP_MSB_CALIB(xcvr_setup_value));
- val |= UTMIP_XCVR_LSFSLEW(config->xcvr_lsfslew);
- val |= UTMIP_XCVR_LSRSLEW(config->xcvr_lsrslew);
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- val |= UTMIP_XCVR_HSSLEW_MSB(0x8);
-#endif
- writel(val, base + UTMIP_XCVR_CFG0);
-
- val = readl(base + UTMIP_XCVR_CFG1);
- val &= ~(UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN |
- UTMIP_FORCE_PDDR_POWERDOWN | UTMIP_XCVR_TERM_RANGE_ADJ(~0));
- val |= UTMIP_XCVR_TERM_RANGE_ADJ(config->term_range_adj);
- writel(val, base + UTMIP_XCVR_CFG1);
-
- val = readl(base + UTMIP_BAT_CHRG_CFG0);
- if (phy->mode == TEGRA_USB_PHY_MODE_HOST)
- val |= UTMIP_PD_CHRG;
- else
- val &= ~UTMIP_PD_CHRG;
- writel(val, base + UTMIP_BAT_CHRG_CFG0);
-
- val = readl(base + UTMIP_BIAS_CFG1);
- val &= ~UTMIP_BIAS_PDTRK_COUNT(~0);
- val |= UTMIP_BIAS_PDTRK_COUNT(phy->freq->pdtrk_count);
- writel(val, base + UTMIP_BIAS_CFG1);
-
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- val = readl(base + UTMIP_SPARE_CFG0);
- val &= ~FUSE_SETUP_SEL;
- writel(val, base + UTMIP_SPARE_CFG0);
-
- if (phy->instance == 2) {
- val = readl(base + UTMIP_SPARE_CFG0);
- val |= FUSE_SETUP_SEL;
- writel(val, base + UTMIP_SPARE_CFG0);
-
- val = readl(base + USB_SUSP_CTRL);
- val |= UTMIP_PHY_ENABLE;
- writel(val, base + USB_SUSP_CTRL);
- }
-#else
- val = readl(base + UTMIP_SPARE_CFG0);
- val &= ~FUSE_SETUP_SEL;
- val |= FUSE_ATERM_SEL;
- writel(val, base + UTMIP_SPARE_CFG0);
-
- val = readl(base + USB_SUSP_CTRL);
- val |= UTMIP_PHY_ENABLE;
- writel(val, base + USB_SUSP_CTRL);
-#endif
-
- val = readl(base + USB_SUSP_CTRL);
- val &= ~UTMIP_RESET;
- writel(val, base + USB_SUSP_CTRL);
-
- if (phy->instance == 0) {
- val = readl(base + USB1_LEGACY_CTRL);
- val &= ~USB1_VBUS_SENSE_CTL_MASK;
- val |= USB1_VBUS_SENSE_CTL_A_SESS_VLD;
- writel(val, base + USB1_LEGACY_CTRL);
-
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- val = readl(base + USB_SUSP_CTRL);
- val &= ~USB_SUSP_SET;
- writel(val, base + USB_SUSP_CTRL);
-#endif
+ phy->ctrlr_clk = clk_get(&phy->pdev->dev, NULL);
+ if (IS_ERR(phy->ctrlr_clk)) {
+ dev_err(&phy->pdev->dev, "Can't get controller clock\n");
+ err = PTR_ERR(phy->ctrlr_clk);
+ goto fail_ctrlr_clk;
}
- utmi_phy_clk_enable(phy);
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- if (phy->instance == 2) {
- val = readl(base + USB_PORTSC1);
- val &= ~USB_PORTSC1_PTS(~0);
- writel(val, base + USB_PORTSC1);
- }
-#else
- if (phy->instance == 0)
- utmip_phy_enable_trking_data(phy);
+ if (phy->pdata->op_mode == TEGRA_USB_OPMODE_HOST)
+ if (phy->pdata->u_data.host.hot_plug ||
+ phy->pdata->u_data.host.remote_wakeup_supported)
+ clk_enable(phy->ctrlr_clk);
- if(phy->instance == 2) {
- writel(0, base + ICUSB_CTRL);
+ phy->sys_clk = clk_get(&phy->pdev->dev, "sclk");
+ if (IS_ERR(phy->sys_clk)) {
+ dev_err(&phy->pdev->dev, "Can't get sclk clock\n");
+ err = PTR_ERR(phy->sys_clk);
+ goto fail_sclk;
}
+ clk_set_rate(phy->sys_clk, 80000000);
- if (phy->mode == TEGRA_USB_PHY_MODE_HOST) {
- val = readl(base + TEGRA_USB_USBMODE_REG_OFFSET);
- writel((val | TEGRA_USB_USBMODE_HOST),
- (base + TEGRA_USB_USBMODE_REG_OFFSET));
+ phy->emc_clk = clk_get(&phy->pdev->dev, "emc");
+ if (IS_ERR(phy->emc_clk)) {
+ dev_err(&phy->pdev->dev, "Can't get emc clock\n");
+ err = PTR_ERR(phy->emc_clk);
+ goto fail_emc;
}
- val = readl(base + HOSTPC1_DEVLC);
- val &= ~HOSTPC1_DEVLC_PTS(~0);
- val |= HOSTPC1_DEVLC_STS;
- writel(val, base + HOSTPC1_DEVLC);
- if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE)
- utmip_powerup_pmc_wake_detect(phy);
-#endif
-
- return 0;
-}
-
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
-static void utmip_setup_pmc_wake_detect(struct tegra_usb_phy *phy)
-{
- unsigned long val, pmc_pad_cfg_val;
- void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
- unsigned int inst = phy->instance;
- void __iomem *base = phy->regs;
- bool port_connected;
- enum tegra_usb_phy_port_speed port_speed;
-
- /* check for port connect status */
- val = readl(base + USB_PORTSC1);
- port_connected = val & USB_PORTSC1_CCS;
-
- if (!port_connected)
- return;
-
- port_speed = (readl(base + HOSTPC1_DEVLC) >> 25) &
- HOSTPC1_DEVLC_PSPD_MASK;
- /*Set PMC MASTER bits to do the following
- * a. Take over the UTMI drivers
- * b. set up such that it will take over resume
- * if remote wakeup is detected
- * Prepare PMC to take over suspend-wake detect-drive resume until USB
- * controller ready
- */
-
- /* disable master enable in PMC */
- val = readl(pmc_base + PMC_SLEEP_CFG);
- val &= ~UTMIP_MASTER_ENABLE(inst);
- writel(val, pmc_base + PMC_SLEEP_CFG);
-
- /* UTMIP_PWR_PX=1 for power savings mode */
- val = readl(pmc_base + PMC_UTMIP_MASTER_CONFIG);
- val |= UTMIP_PWR(inst);
- writel(val, pmc_base + PMC_UTMIP_MASTER_CONFIG);
-
- /* config debouncer */
- val = readl(pmc_base + PMC_USB_DEBOUNCE);
- val &= ~UTMIP_LINE_DEB_CNT(~0);
- val |= UTMIP_LINE_DEB_CNT(1);
- writel(val, pmc_base + PMC_USB_DEBOUNCE);
-
- /* Make sure nothing is happening on the line with respect to PMC */
- val = readl(pmc_base + PMC_UTMIP_UHSIC_FAKE);
- val &= ~USBOP_VAL(inst);
- val &= ~USBON_VAL(inst);
- writel(val, pmc_base + PMC_UTMIP_UHSIC_FAKE);
-
- /* Make sure wake value for line is none */
- val = readl(pmc_base + PMC_SLEEPWALK_CFG);
- val &= ~UTMIP_LINEVAL_WALK_EN(inst);
- writel(val, pmc_base + PMC_SLEEPWALK_CFG);
- val = readl(pmc_base + PMC_SLEEP_CFG);
- val &= ~UTMIP_WAKE_VAL(inst, ~0);
- val |= UTMIP_WAKE_VAL(inst, WAKE_VAL_NONE);
- writel(val, pmc_base + PMC_SLEEP_CFG);
-
- /* turn off pad detectors */
- val = readl(pmc_base + PMC_USB_AO);
- val |= (USBOP_VAL_PD(inst) | USBON_VAL_PD(inst));
- writel(val, pmc_base + PMC_USB_AO);
-
- /* Remove fake values and make synchronizers work a bit */
- val = readl(pmc_base + PMC_UTMIP_UHSIC_FAKE);
- val &= ~USBOP_VAL(inst);
- val &= ~USBON_VAL(inst);
- writel(val, pmc_base + PMC_UTMIP_UHSIC_FAKE);
-
- /* Enable which type of event can trigger a walk,
- in this case usb_line_wake */
- val = readl(pmc_base + PMC_SLEEPWALK_CFG);
- val |= UTMIP_LINEVAL_WALK_EN(inst);
- writel(val, pmc_base + PMC_SLEEPWALK_CFG);
-
- /* Enable which type of event can trigger a walk,
- * in this case usb_line_wake */
- val = readl(pmc_base + PMC_SLEEPWALK_CFG);
- val |= UTMIP_LINEVAL_WALK_EN(inst);
- writel(val, pmc_base + PMC_SLEEPWALK_CFG);
-
- /* Clear the walk pointers and wake alarm */
- val = readl(pmc_base + PMC_TRIGGERS);
- val |= UTMIP_CLR_WAKE_ALARM(inst) | UTMIP_CLR_WALK_PTR(inst);
- writel(val, pmc_base + PMC_TRIGGERS);
-
-
- /* Capture FS/LS pad configurations */
- pmc_pad_cfg_val = readl(pmc_base + PMC_PAD_CFG);
- val = readl(pmc_base + PMC_TRIGGERS);
- val |= UTMIP_CAP_CFG(inst);
- writel(val, pmc_base + PMC_TRIGGERS);
- udelay(1);
- pmc_pad_cfg_val = readl(pmc_base + PMC_PAD_CFG);
-
- /* BIAS MASTER_ENABLE=0 */
- val = readl(pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL);
- val &= ~BIAS_MASTER_PROG_VAL;
- writel(val, pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL);
-
- /* program walk sequence, maintain a J, followed by a driven K
- * to signal a resume once an wake event is detected */
- val = readl(pmc_base + PMC_SLEEPWALK_REG(inst));
- val &= ~UTMIP_AP_A;
- val |= UTMIP_USBOP_RPD_A | UTMIP_USBON_RPD_A| UTMIP_AN_A | UTMIP_HIGHZ_A |
- UTMIP_USBOP_RPD_B | UTMIP_USBON_RPD_B | UTMIP_AP_B | UTMIP_AN_B |
- UTMIP_USBOP_RPD_C | UTMIP_USBON_RPD_C | UTMIP_AP_C | UTMIP_AN_C |
- UTMIP_USBOP_RPD_D | UTMIP_USBON_RPD_D | UTMIP_AP_D | UTMIP_AN_D;
- writel(val, pmc_base + PMC_SLEEPWALK_REG(inst));
-
- if (port_speed == TEGRA_USB_PHY_PORT_SPEED_LOW) {
- val = readl(pmc_base + PMC_SLEEPWALK_REG(inst));
- val &= ~(UTMIP_AN_B | UTMIP_HIGHZ_B | UTMIP_AN_C |
- UTMIP_HIGHZ_C | UTMIP_AN_D | UTMIP_HIGHZ_D);
- writel(val, pmc_base + PMC_SLEEPWALK_REG(inst));
- } else {
- val = readl(pmc_base + PMC_SLEEPWALK_REG(inst));
- val &= ~(UTMIP_AP_B | UTMIP_HIGHZ_B | UTMIP_AP_C |
- UTMIP_HIGHZ_C | UTMIP_AP_D | UTMIP_HIGHZ_D);
- writel(val, pmc_base + PMC_SLEEPWALK_REG(inst));
- }
+ if(phy->pdata->has_hostpc)
+ clk_set_rate(phy->emc_clk, 100000000);
+ else
+ clk_set_rate(phy->emc_clk, 300000000);
- /* turn on pad detectors */
- val = readl(pmc_base + PMC_USB_AO);
- val &= ~(USBOP_VAL_PD(inst) | USBON_VAL_PD(inst));
- writel(val, pmc_base + PMC_USB_AO);
+ return err;
- /* Add small delay before usb detectors provide stable line values */
- mdelay(1);
+fail_emc:
+ clk_put(phy->sys_clk);
- /* Program thermally encoded RCTRL_VAL, TCTRL_VAL into PMC space */
- val = readl(pmc_base + PMC_UTMIP_TERM_PAD_CFG);
- val = PMC_TCTRL_VAL(utmip_tctrl_val) | PMC_RCTRL_VAL(utmip_rctrl_val);
- writel(val, pmc_base + PMC_UTMIP_TERM_PAD_CFG);
+fail_sclk:
+ clk_put(phy->ctrlr_clk);
- phy->remote_wakeup = false;
+fail_ctrlr_clk:
+ clk_disable(phy->pllu_clk);
+ clk_put(phy->pllu_clk);
- /* Turn over pad configuration to PMC for line wake events*/
- val = readl(pmc_base + PMC_SLEEP_CFG);
- val &= ~UTMIP_WAKE_VAL(inst, ~0);
- val |= UTMIP_WAKE_VAL(inst, WAKE_VAL_ANY);
- val |= UTMIP_RCTRL_USE_PMC(inst) | UTMIP_TCTRL_USE_PMC(inst);
- val |= UTMIP_MASTER_ENABLE(inst) | UTMIP_FSLS_USE_PMC(inst);
- writel(val, pmc_base + PMC_SLEEP_CFG);
+fail_pll:
- val = readl(base + UTMIP_PMC_WAKEUP0);
- val |= EVENT_INT_ENB;
- writel(val, base + UTMIP_PMC_WAKEUP0);
+ return err;
}
-#endif
-static int utmi_phy_power_off(struct tegra_usb_phy *phy, bool is_dpd)
+struct tegra_usb_phy *tegra_usb_phy_open(struct platform_device *pdev)
{
- unsigned long val;
- void __iomem *base = phy->regs;
-
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- if (phy->mode == TEGRA_USB_PHY_MODE_HOST)
- utmip_setup_pmc_wake_detect(phy);
- else
- utmip_powerdown_pmc_wake_detect(phy);
-#endif
- if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) {
- val = readl(base + USB_SUSP_CTRL);
- val &= ~USB_WAKEUP_DEBOUNCE_COUNT(~0);
- val |= USB_WAKE_ON_CNNT_EN_DEV | USB_WAKEUP_DEBOUNCE_COUNT(5);
- writel(val, base + USB_SUSP_CTRL);
- }
+ struct tegra_usb_phy *phy;
+ struct tegra_usb_platform_data *pdata;
+ struct resource *res;
+ int err;
- if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) {
- val = readl(base + UTMIP_BAT_CHRG_CFG0);
- val |= UTMIP_PD_CHRG;
- writel(val, base + UTMIP_BAT_CHRG_CFG0);
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, pdev->id);
+ pdata = dev_get_platdata(&pdev->dev);
+ if (!pdata) {
+ dev_err(&pdev->dev, "inst:[%d] Platform data missing\n",
+ pdev->id);
+ return ERR_PTR(-EINVAL);
}
- if (phy->instance != 2) {
- val = readl(base + UTMIP_XCVR_CFG0);
- val |= (UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN |
- UTMIP_FORCE_PDZI_POWERDOWN);
- writel(val, base + UTMIP_XCVR_CFG0);
+ phy = kzalloc(sizeof(struct tegra_usb_phy), GFP_KERNEL);
+ if (!phy) {
+ ERR("inst:[%d] malloc usb phy failed\n", pdev->id);
+ return ERR_PTR(-ENOMEM);
}
- val = readl(base + UTMIP_XCVR_CFG1);
- val |= UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN |
- UTMIP_FORCE_PDDR_POWERDOWN;
- writel(val, base + UTMIP_XCVR_CFG1);
-
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- val = readl(base + UTMIP_BIAS_CFG1);
- val |= UTMIP_BIAS_PDTRK_COUNT(0x5);
- writel(val, base + UTMIP_BIAS_CFG1);
-#endif
- if (phy->hotplug) {
- val = readl(base + USB_PORTSC1);
- val |= USB_PORTSC1_WKCN;
- writel(val, base + USB_PORTSC1);
- }
- if (phy->instance != 0) {
- val = readl(base + UTMIP_BIAS_CFG0);
- val |= UTMIP_OTGPD;
- writel(val, base + UTMIP_BIAS_CFG0);
+ phy->pdata = kzalloc(sizeof(struct tegra_usb_platform_data), GFP_KERNEL);
+ if (!phy->pdata) {
+ ERR("inst:[%d] malloc usb phy pdata failed\n", pdev->id);
+ kfree(phy);
+ return ERR_PTR(-ENOMEM);
}
- utmi_phy_clk_disable(phy);
-
- utmip_pad_power_off(phy, true);
- return 0;
-}
+ memcpy(phy->pdata, pdata, sizeof(struct tegra_usb_platform_data));
+ phy->pdev = pdev;
+ phy->inst = pdev->id;
-static void utmip_phy_disable_pmc_bus_ctrl(struct tegra_usb_phy *phy)
-{
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- unsigned long val;
- void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
- unsigned int inst = phy->instance;
- void __iomem *base = phy->regs;
-
- val = readl(pmc_base + PMC_SLEEP_CFG);
- val &= ~UTMIP_WAKE_VAL(inst, 0x0);
- val |= UTMIP_WAKE_VAL(inst, WAKE_VAL_NONE);
- writel(val, pmc_base + PMC_SLEEP_CFG);
-
- val = readl(pmc_base + PMC_TRIGGERS);
- val |= UTMIP_CLR_WAKE_ALARM(inst) | UTMIP_CLR_WALK_PTR(inst);
- writel(val, pmc_base + PMC_TRIGGERS);
-
- val = readl(base + UTMIP_PMC_WAKEUP0);
- val &= ~EVENT_INT_ENB;
- writel(val, base + UTMIP_PMC_WAKEUP0);
-
- /* Disable PMC master mode by clearing MASTER_EN */
- val = readl(pmc_base + PMC_SLEEP_CFG);
- val &= ~(UTMIP_RCTRL_USE_PMC(inst) | UTMIP_TCTRL_USE_PMC(inst) |
- UTMIP_FSLS_USE_PMC(inst) | UTMIP_MASTER_ENABLE(inst));
- writel(val, pmc_base + PMC_SLEEP_CFG);
-
- val = readl(pmc_base + PMC_TRIGGERS);
- val &= ~UTMIP_CAP_CFG(inst);
- writel(val, pmc_base + PMC_TRIGGERS);
-
- /* turn off pad detectors */
- val = readl(pmc_base + PMC_USB_AO);
- val |= (USBOP_VAL_PD(inst) | USBON_VAL_PD(inst));
- writel(val, pmc_base + PMC_USB_AO);
-
- phy->remote_wakeup = false;
-#endif
-}
+ print_usb_plat_data_info(phy);
-static void utmi_phy_enable_obs_bus(struct tegra_usb_phy *phy,
- enum tegra_usb_phy_port_speed port_speed)
-{
- unsigned long val;
- void __iomem *base = phy->regs;
-
- /* (2LS WAR)is not required for LS and FS devices and is only for HS */
- if (port_speed != TEGRA_USB_PHY_PORT_SPEED_HIGH) {
- /* do not enable the OBS bus */
- val = readl(base + UTMIP_MISC_CFG0);
- val &= ~UTMIP_DPDM_OBSERVE_SEL(~0);
- writel(val, base + UTMIP_MISC_CFG0);
- return;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ ERR("inst:[%d] failed to get I/O memory\n", phy->inst);
+ err = -ENXIO;
+ goto fail_io;
}
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- /* Force DP/DM pulldown active for Host mode */
- val = readl(base + UTMIP_MISC_CFG0);
- val |= FORCE_PULLDN_DM | FORCE_PULLDN_DP |
- COMB_TERMS | ALWAYS_FREE_RUNNING_TERMS;
- writel(val, base + UTMIP_MISC_CFG0);
-#endif
- val = readl(base + UTMIP_MISC_CFG0);
- val &= ~UTMIP_DPDM_OBSERVE_SEL(~0);
- if (port_speed == TEGRA_USB_PHY_PORT_SPEED_LOW)
- val |= UTMIP_DPDM_OBSERVE_SEL_FS_J;
- else
- val |= UTMIP_DPDM_OBSERVE_SEL_FS_K;
- writel(val, base + UTMIP_MISC_CFG0);
- udelay(1);
-
- val = readl(base + UTMIP_MISC_CFG0);
- val |= UTMIP_DPDM_OBSERVE;
- writel(val, base + UTMIP_MISC_CFG0);
- udelay(10);
-}
-static void utmi_phy_disable_obs_bus(struct tegra_usb_phy *phy)
-{
- unsigned long val;
- void __iomem *base = phy->regs;
-
- /* check if OBS bus is already enabled */
- val = readl(base + UTMIP_MISC_CFG0);
- if (val & UTMIP_DPDM_OBSERVE) {
- /* Change the UTMIP OBS bus to drive SE0 */
- val = readl(base + UTMIP_MISC_CFG0);
- val &= ~UTMIP_DPDM_OBSERVE_SEL(~0);
- val |= UTMIP_DPDM_OBSERVE_SEL_FS_SE0;
- writel(val, base + UTMIP_MISC_CFG0);
-
- /* Wait for 3us(2 LS bit times) */
- udelay (3);
-
- /* Release UTMIP OBS bus */
- val = readl(base + UTMIP_MISC_CFG0);
- val &= ~UTMIP_DPDM_OBSERVE;
- writel(val, base + UTMIP_MISC_CFG0);
-
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- /* Release DP/DM pulldown for Host mode */
- val = readl(base + UTMIP_MISC_CFG0);
- val &= ~(FORCE_PULLDN_DM | FORCE_PULLDN_DP |
- COMB_TERMS | ALWAYS_FREE_RUNNING_TERMS);
- writel(val, base + UTMIP_MISC_CFG0);
-#endif
+ phy->regs = ioremap(res->start, resource_size(res));
+ if (!phy->regs) {
+ ERR("inst:[%d] Failed to remap I/O memory\n", phy->inst);
+ err = -ENOMEM;
+ goto fail_io;
}
-}
-
-static int utmi_phy_preresume(struct tegra_usb_phy *phy, bool remote_wakeup)
-{
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- unsigned long val;
- void __iomem *base = phy->regs;
- enum tegra_usb_phy_port_speed port_speed;
-
- val = readl(base + UTMIP_TX_CFG0);
- val |= UTMIP_HS_DISCON_DISABLE;
- writel(val, base + UTMIP_TX_CFG0);
-
- port_speed = (readl(base + USB_PORTSC1) >> 26) & 0x3;
- if (remote_wakeup && (port_speed == TEGRA_USB_PHY_PORT_SPEED_HIGH)) {
- val = readl(base + USB_USBCMD);
- val &= ~USB_USBCMD_RS;
- writel(val, base + USB_USBCMD);
- if (utmi_wait_register(base + USB_USBSTS,
- USB_USBSTS_HCH, USB_USBSTS_HCH) < 0) {
- pr_err("%s: timeout waiting for stopping controller\n", __func__);
- return -ETIMEDOUT;
- }
+ phy->vdd_reg = regulator_get(NULL, "avdd_usb");
+ if (IS_ERR_OR_NULL(phy->vdd_reg)) {
+ ERR("inst:[%d] couldn't get regulator avdd_usb: %ld\n",
+ phy->inst, PTR_ERR(phy->vdd_reg));
+ phy->vdd_reg = NULL;
}
- utmi_phy_enable_obs_bus(phy, port_speed);
-#else
- unsigned long val;
- void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
- unsigned int inst = phy->instance;
- void __iomem *base = phy->regs;
- enum tegra_usb_phy_port_speed port_speed;
-
- val = readl(pmc_base + PMC_SLEEP_CFG);
- if (val & UTMIP_MASTER_ENABLE(inst)) {
- if (!remote_wakeup)
- utmip_phy_disable_pmc_bus_ctrl(phy);
- } else {
- port_speed = (readl(base + HOSTPC1_DEVLC) >> 25) &
- HOSTPC1_DEVLC_PSPD_MASK;
- utmi_phy_enable_obs_bus(phy, port_speed);
+ err = tegra_usb_phy_get_clocks(phy);
+ if (err) {
+ ERR("inst:[%d] Failed to init clocks\n", phy->inst);
+ goto fail_clk;
}
-#endif
- return 0;
-}
-
-static int utmi_phy_postresume(struct tegra_usb_phy *phy, bool is_dpd)
-{
- unsigned long val;
-#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
- void __iomem *base = phy->regs;
-#else
- void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
- unsigned int inst = phy->instance;
-#endif
-
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- val = readl(pmc_base + PMC_SLEEP_CFG);
- /* if PMC is not disabled by now then disable it */
- if (val & UTMIP_MASTER_ENABLE(inst)) {
- utmip_phy_disable_pmc_bus_ctrl(phy);
- }
- utmi_phy_disable_obs_bus(phy);
-#else
- val = readl(base + USB_USBCMD);
- if (val & USB_USBCMD_RS) {
- val &= ~USB_USBCMD_RS;
- writel(val, base + USB_USBCMD);
- if (utmi_wait_register(base + USB_USBSTS,
- USB_USBSTS_HCH, USB_USBSTS_HCH) < 0) {
- pr_err("%s: timeout waiting for stopping controller\n", __func__);
- return -ETIMEDOUT;
+ if (phy->pdata->op_mode == TEGRA_USB_OPMODE_DEVICE) {
+ if (phy->pdata->u_data.dev.vbus_pmu_irq) {
+ err = request_threaded_irq(
+ phy->pdata->u_data.dev.vbus_pmu_irq,
+ NULL, usb_phy_dev_vbus_pmu_irq_thr,
+ IRQF_SHARED, "usb_pmu_vbus_irq", phy);
+ if (err) {
+ ERR("inst:[%d] Failed to register IRQ\n",
+ phy->inst);
+ goto fail_init;
+ }
+ } else {
+ clk_enable(phy->ctrlr_clk);
}
+ } else {
+ if (phy->pdata->u_data.host.vbus_reg) {
+ phy->vbus_reg = regulator_get(NULL,
+ phy->pdata->u_data.host.vbus_reg);
+ if (WARN_ON(IS_ERR_OR_NULL(phy->vbus_reg))) {
+ ERR("failed to get regulator vdd_vbus_usb: %ld,\
+ instance : %d\n", PTR_ERR(phy->vbus_reg),
+ phy->inst);
+ err = PTR_ERR(phy->vbus_reg);
+ goto fail_init;
+ }
+ } else {
+ int gpio = phy->pdata->u_data.host.vbus_gpio;
+ if (gpio != -1) {
+ if (gpio_request(gpio, "usb_host_vbus") < 0) {
+ ERR("inst:[%d] host vbus gpio \
+ req failed\n", phy->inst);
+ goto fail_init;
+ }
+ if (gpio < TEGRA_NR_GPIOS)
+ tegra_gpio_enable(gpio);
+ if (gpio_direction_output(gpio, !phy->pdata->u_data.host.vbus_gpio_inverted) < 0) {
+ ERR("inst:[%d] host vbus gpio \
+ dir failed\n", phy->inst);
+ goto fail_init;
+ }
+ }
+ }
+ usb_host_vbus_enable(phy, true);
}
- writel(val, base + USB_USBCMD);
- utmi_phy_disable_obs_bus(phy);
- val = readl(base + USB_USBCMD);
- val |= USB_USBCMD_RS;
- writel(val, base + USB_USBCMD);
- val = readl(base + UTMIP_TX_CFG0);
- val &= ~UTMIP_HS_DISCON_DISABLE;
- writel(val, base + UTMIP_TX_CFG0);
-#endif
-
-
- return 0;
-}
-
-static int uhsic_phy_postsuspend(struct tegra_usb_phy *phy, bool is_dpd)
-{
- struct tegra_uhsic_config *uhsic_config = phy->config;
-
- if (uhsic_config->postsuspend)
- uhsic_config->postsuspend();
-
- return 0;
-}
-
-static int uhsic_phy_preresume(struct tegra_usb_phy *phy, bool remote_wakeup)
-{
- struct tegra_uhsic_config *uhsic_config = phy->config;
-
- if (uhsic_config->preresume)
- uhsic_config->preresume();
-
- return 0;
-}
-static int uhsic_phy_postresume(struct tegra_usb_phy *phy, bool is_dpd)
-{
- unsigned long val;
- void __iomem *base = phy->regs;
-
- val = readl(base + USB_TXFILLTUNING);
- if ((val & USB_FIFO_TXFILL_MASK) != USB_FIFO_TXFILL_THRES(0x10)) {
- val = USB_FIFO_TXFILL_THRES(0x10);
- writel(val, base + USB_TXFILLTUNING);
+ err = tegra_usb_phy_init_ops(phy);
+ if (err) {
+ ERR("inst:[%d] Failed to init ops\n", phy->inst);
+ goto fail_init;
}
- return 0;
-}
-
-static void utmi_phy_restore_start(struct tegra_usb_phy *phy,
- enum tegra_usb_phy_port_speed port_speed)
-{
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- unsigned long val;
- void __iomem *base = phy->regs;
+ if (phy->pdata->ops && phy->pdata->ops->open)
+ phy->pdata->ops->open();
- val = readl(base + UTMIP_MISC_CFG0);
- val &= ~UTMIP_DPDM_OBSERVE_SEL(~0);
- if (port_speed == TEGRA_USB_PHY_PORT_SPEED_LOW)
- val |= UTMIP_DPDM_OBSERVE_SEL_FS_K;
- else
- val |= UTMIP_DPDM_OBSERVE_SEL_FS_J;
- writel(val, base + UTMIP_MISC_CFG0);
- udelay(1);
-
- val = readl(base + UTMIP_MISC_CFG0);
- val |= UTMIP_DPDM_OBSERVE;
- writel(val, base + UTMIP_MISC_CFG0);
- udelay(10);
-#else
- unsigned long val;
- void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
- int inst = phy->instance;
-
- val = readl(pmc_base + UTMIP_UHSIC_STATUS);
- /* check whether we wake up from the remote resume */
- if (UTMIP_WALK_PTR_VAL(inst) & val) {
- phy->remote_wakeup = true;
- } else {
- if (!((UTMIP_USBON_VAL(phy->instance) |
- UTMIP_USBOP_VAL(phy->instance)) & val)) {
- utmip_phy_disable_pmc_bus_ctrl(phy);
+ if (phy->ops && phy->ops->open) {
+ err = phy->ops->open(phy);
+ if (err) {
+ ERR("inst:[%d] Failed to open hw ops\n", phy->inst);
+ goto fail_init;
}
}
- utmi_phy_enable_obs_bus(phy, port_speed);
-#endif
-}
-static void utmi_phy_restore_end(struct tegra_usb_phy *phy)
-{
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- unsigned long val;
- void __iomem *base = phy->regs;
+ return phy;
- val = readl(base + UTMIP_MISC_CFG0);
- val &= ~UTMIP_DPDM_OBSERVE;
- writel(val, base + UTMIP_MISC_CFG0);
- udelay(10);
-#else
- unsigned long val;
- void __iomem *base = phy->regs;
- int wait_time_us = 3000; /* FPR should be set by this time */
-
- /* check whether we wake up from the remote resume */
- if (phy->remote_wakeup) {
- /* wait until FPR bit is set automatically on remote resume */
- do {
- val = readl(base + USB_PORTSC1);
- udelay(1);
- if (wait_time_us == 0) {
- utmip_phy_disable_pmc_bus_ctrl(phy);
- tegra_usb_phy_postresume(phy, false);
- return;
+fail_init:
+ tegra_usb_phy_release_clocks(phy);
+
+ if (phy->pdata->op_mode == TEGRA_USB_OPMODE_DEVICE) {
+ if (phy->pdata->u_data.dev.vbus_pmu_irq)
+ free_irq(phy->pdata->u_data.dev.vbus_pmu_irq, phy);
+ } else {
+ usb_host_vbus_enable(phy, false);
+
+ if (phy->vbus_reg)
+ regulator_put(phy->vbus_reg);
+ else {
+ int gpio = phy->pdata->u_data.host.vbus_gpio;
+ if (gpio != -1) {
+ gpio_set_value_cansleep(gpio, phy->pdata->u_data.host.vbus_gpio_inverted);
+ gpio_free(gpio);
}
- wait_time_us--;
- } while (!(val & USB_PORTSC1_RESUME));
- /* wait for 25 ms to port resume complete */
- msleep(25);
- /* disable PMC master control */
- utmip_phy_disable_pmc_bus_ctrl(phy);
-
- /* Clear PCI and SRI bits to avoid an interrupt upon resume */
- val = readl(base + USB_USBSTS);
- writel(val, base + USB_USBSTS);
- /* wait to avoid SOF if there is any */
- if (utmi_wait_register(base + USB_USBSTS,
- USB_USBSTS_SRI, USB_USBSTS_SRI) < 0) {
- pr_err("%s: timeout waiting for SOF\n", __func__);
}
- tegra_usb_phy_postresume(phy, false);
}
-#endif
-}
-
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
-static void ulpi_set_tristate(bool enable)
-{
- int tristate = (enable)? TEGRA_TRI_TRISTATE : TEGRA_TRI_NORMAL;
-
- tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAA, tristate);
- tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAB, tristate);
- tegra_pinmux_set_tristate(TEGRA_PINGROUP_UDA, tristate);
-}
-#endif
-
-static void ulpi_phy_reset(void __iomem *base)
-{
- unsigned long val;
-
- val = readl(base + USB_SUSP_CTRL);
- val |= UHSIC_RESET;
- writel(val, base + USB_SUSP_CTRL);
-
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- val = readl(base + USB_SUSP_CTRL);
- val |= UTMIP_RESET;
- writel(val, base + USB_SUSP_CTRL);
-#endif
-}
-
-static void ulpi_set_host(void __iomem *base)
-{
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- unsigned long val;
-
- val = readl(base + TEGRA_USB_USBMODE_REG_OFFSET);
- val |= TEGRA_USB_USBMODE_HOST;
- writel(val, base + TEGRA_USB_USBMODE_REG_OFFSET);
-
- val = readl(base + HOSTPC1_DEVLC);
- val |= HOSTPC1_DEVLC_PTS(2);
- writel(val, base + HOSTPC1_DEVLC);
-#endif
-}
-
-static void ulpi_set_trimmer(void __iomem *base, u8 data, u8 sdn, u8 dir)
-{
- unsigned long val;
-
- val = ULPI_DATA_TRIMMER_SEL(data);
- val |= ULPI_STPDIRNXT_TRIMMER_SEL(sdn);
- val |= ULPI_DIR_TRIMMER_SEL(dir);
- writel(val, base + ULPI_TIMING_CTRL_1);
- udelay(10);
-
- val |= ULPI_DATA_TRIMMER_LOAD;
- val |= ULPI_STPDIRNXT_TRIMMER_LOAD;
- val |= ULPI_DIR_TRIMMER_LOAD;
- writel(val, base + ULPI_TIMING_CTRL_1);
-}
-
-static inline void ulpi_pinmux_bypass(struct tegra_usb_phy *phy, bool enable)
-{
- unsigned long val;
- void __iomem *base = phy->regs;
-
- val = readl(base + ULPI_TIMING_CTRL_0);
-
- if (enable)
- val |= ULPI_OUTPUT_PINMUX_BYP;
- else
- val &= ~ULPI_OUTPUT_PINMUX_BYP;
-
- writel(val, base + ULPI_TIMING_CTRL_0);
-}
-
-static void ulpi_phy_restore_start(struct tegra_usb_phy *phy,
- enum tegra_usb_phy_port_speed port_speed)
-{
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- unsigned long val;
- void __iomem *base = phy->regs;
- /*Tristate ulpi interface before USB controller resume*/
- ulpi_set_tristate(true);
+fail_clk:
+ regulator_put(phy->vdd_reg);
+ iounmap(phy->regs);
+fail_io:
+ kfree(phy);
- val = readl(base + ULPI_TIMING_CTRL_0);
- val &= ~ULPI_OUTPUT_PINMUX_BYP;
- writel(val, base + ULPI_TIMING_CTRL_0);
-#endif
+ return ERR_PTR(err);
}
-static void ulpi_phy_restore_end(struct tegra_usb_phy *phy)
-{
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- unsigned long val;
- void __iomem *base = phy->regs;
-
- val = readl(base + ULPI_TIMING_CTRL_0);
- val |= ULPI_OUTPUT_PINMUX_BYP;
- writel(val, base + ULPI_TIMING_CTRL_0);
- ulpi_set_tristate(false);
-#endif
-}
-static int ulpi_phy_power_on(struct tegra_usb_phy *phy, bool is_dpd)
+void tegra_usb_phy_close(struct tegra_usb_phy *phy)
{
- int ret;
- unsigned long val;
- void __iomem *base = phy->regs;
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- struct tegra_ulpi_config *config = phy->config;
-#endif
-
- if (phy->clk)
- clk_enable(phy->clk);
-
- msleep(1);
-
- if (!phy->initialized) {
- phy->initialized = 1;
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- gpio_direction_output(config->reset_gpio, 0);
- msleep(5);
- gpio_direction_output(config->reset_gpio, 1);
-#endif
- }
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
- ulpi_phy_reset(base);
- ulpi_set_host(base);
+ if (phy->ops && phy->ops->close)
+ phy->ops->close(phy);
- val = readl(base + ULPI_TIMING_CTRL_0);
- val |= ULPI_OUTPUT_PINMUX_BYP | ULPI_CLKOUT_PINMUX_BYP;
- writel(val, base + ULPI_TIMING_CTRL_0);
+ if (phy->pdata->ops && phy->pdata->ops->close)
+ phy->pdata->ops->close();
- val = readl(base + USB_SUSP_CTRL);
- val |= ULPI_PHY_ENABLE;
- writel(val, base + USB_SUSP_CTRL);
-
- val = readl(base + USB_SUSP_CTRL);
- val |= USB_SUSP_CLR;
- writel(val, base + USB_SUSP_CTRL);
-
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID,
- USB_PHY_CLK_VALID) < 0)
- pr_err("%s: timeout waiting for phy to stabilize\n", __func__);
-
- if (utmi_wait_register(base + USB_SUSP_CTRL, USB_CLKEN, USB_CLKEN) < 0)
- pr_err("%s: timeout waiting for AHB clock\n", __func__);
-#else
- udelay(100);
-#endif
-
- val = readl(base + USB_SUSP_CTRL);
- val &= ~USB_SUSP_CLR;
- writel(val, base + USB_SUSP_CTRL);
-
- val = 0;
- writel(val, base + ULPI_TIMING_CTRL_1);
-
- ulpi_set_trimmer(base, 4, 4, 4);
-
- /* Fix VbusInvalid due to floating VBUS */
- ret = otg_io_write(phy->ulpi, 0x40, 0x08);
- if (ret) {
- pr_err("%s: ulpi write failed\n", __func__);
- return ret;
+ if (phy->pdata->op_mode == TEGRA_USB_OPMODE_DEVICE) {
+ if (phy->pdata->u_data.dev.vbus_pmu_irq)
+ free_irq(phy->pdata->u_data.dev.vbus_pmu_irq, phy);
+ else
+ clk_disable(phy->ctrlr_clk);
+ } else {
+ usb_host_vbus_enable(phy, false);
+
+ if (phy->vbus_reg)
+ regulator_put(phy->vbus_reg);
+ else {
+ int gpio = phy->pdata->u_data.host.vbus_gpio;
+ if (gpio != -1) {
+ gpio_set_value_cansleep(gpio, phy->pdata->u_data.host.vbus_gpio_inverted);
+ gpio_free(gpio);
+ }
+ }
}
- ret = otg_io_write(phy->ulpi, 0x80, 0x0B);
- if (ret) {
- pr_err("%s: ulpi write failed\n", __func__);
- return ret;
+ if (phy->vdd_reg) {
+ if (phy->vdd_reg_on)
+ regulator_disable(phy->vdd_reg);
+ regulator_put(phy->vdd_reg);
}
- val = readl(base + USB_PORTSC1);
- val |= USB_PORTSC1_WKOC | USB_PORTSC1_WKDS | USB_PORTSC1_WKCN;
- writel(val, base + USB_PORTSC1);
-
-//should really all be done in some board specific enable_vbus()
-#ifdef CONFIG_MACH_COLIBRI_T20
- /* Fix Ethernet detection faults */
- mdelay(100);
-
-#define ETHERNET_VBUS_GPIO TEGRA_GPIO_PBB1
-#define ETHERNET_RESET_GPIO TEGRA_GPIO_PV4
- tegra_gpio_enable(ETHERNET_VBUS_GPIO);
- gpio_request(ETHERNET_VBUS_GPIO, "ethernet_vbus");
- gpio_direction_output(ETHERNET_VBUS_GPIO, 1);
- gpio_export(ETHERNET_VBUS_GPIO, false);
+ tegra_usb_phy_release_clocks(phy);
- tegra_gpio_enable(ETHERNET_RESET_GPIO);
- gpio_request(ETHERNET_RESET_GPIO, "ethernet_reset");
- gpio_direction_output(ETHERNET_RESET_GPIO, 1);
- gpio_export(ETHERNET_RESET_GPIO, false);
-#endif /* CONFIG_MACH_COLIBRI_T20 */
-
- return 0;
+ kfree(phy->pdata);
+ kfree(phy);
}
-static int ulpi_phy_power_off(struct tegra_usb_phy *phy, bool is_dpd)
+irqreturn_t tegra_usb_phy_irq(struct tegra_usb_phy *phy)
{
- unsigned long val;
- void __iomem *base = phy->regs;
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- int ret;
-
- /* Disable VbusValid, SessEnd comparators */
- ret = otg_io_write(phy->ulpi, 0x00, 0x0D);
- if (ret)
- pr_err("%s: ulpi write 0x0D failed\n", __func__);
-
- ret = otg_io_write(phy->ulpi, 0x00, 0x10);
- if (ret)
- pr_err("%s: ulpi write 0x10 failed\n", __func__);
-
- /* Disable IdFloat comparator */
- ret = otg_io_write(phy->ulpi, 0x00, 0x19);
- if (ret)
- pr_err("%s: ulpi write 0x19 failed\n", __func__);
-
- ret = otg_io_write(phy->ulpi, 0x00, 0x1D);
- if (ret)
- pr_err("%s: ulpi write 0x1D failed\n", __func__);
-
- /* Clear WKCN/WKDS/WKOC wake-on events that can cause the USB
- * Controller to immediately bring the ULPI PHY out of low power
- */
- val = readl(base + USB_PORTSC1);
- val &= ~(USB_PORTSC1_WKOC | USB_PORTSC1_WKDS | USB_PORTSC1_WKCN);
- writel(val, base + USB_PORTSC1);
+ irqreturn_t status = IRQ_HANDLED;
- /* Put the PHY in the low power mode */
- val = readl(base + USB_PORTSC1);
- val |= USB_PORTSC1_PHCD;
- writel(val, base + USB_PORTSC1);
+ if (phy->ops && phy->ops->irq)
+ status = phy->ops->irq(phy);
- if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, 0) < 0)
- pr_err("%s: timeout waiting for phy to stop\n", __func__);
-#else
- val = readl(base + HOSTPC1_DEVLC);
- val &= ~(HOSTPC1_DEVLC_PHCD);
- writel(val, base + HOSTPC1_DEVLC);
-#endif
-
- if(phy->clk)
- clk_disable(phy->clk);
-
- return 0;
-}
-
-static inline void null_phy_set_tristate(bool enable)
-{
- int tristate = (enable) ? TEGRA_TRI_TRISTATE : TEGRA_TRI_NORMAL;
-
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- tegra_pinmux_set_tristate(TEGRA_PINGROUP_UDA, tristate);
- tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAA, tristate);
- tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAB, tristate);
-#else
- tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA0, tristate);
- tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA1, tristate);
- tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA2, tristate);
- tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA3, tristate);
- tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA4, tristate);
- tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA5, tristate);
- tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA6, tristate);
- tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA7, tristate);
- tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_NXT, tristate);
-
- if (enable)
- tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DIR, tristate);
-#endif
+ return status;
}
-
-static void null_phy_restore_start(struct tegra_usb_phy *phy,
- enum tegra_usb_phy_port_speed port_speed)
+int tegra_usb_phy_init(struct tegra_usb_phy *phy)
{
- struct tegra_ulpi_config *config = phy->config;
-
- if (config->phy_restore_start)
- config->phy_restore_start();
-}
+ int status = 0;
-static void null_phy_restore_end(struct tegra_usb_phy *phy)
-{
- unsigned long val;
- void __iomem *base = phy->regs;
- struct tegra_ulpi_config *config = phy->config;
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
- /* disable ULPI pinmux bypass */
- ulpi_pinmux_bypass(phy, false);
+ if (phy->pdata->ops && phy->pdata->ops->init)
+ phy->pdata->ops->init();
- /* driving linestate using GPIO */
- gpio_set_value(config->ulpi_d0_gpio, 0);
- gpio_set_value(config->ulpi_d1_gpio, 0);
+ if (phy->ops && phy->ops->init)
+ status = phy->ops->init(phy);
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- /* driving DIR high */
- gpio_set_value(config->ulpi_dir_gpio, 1);
-#endif
-
- /* remove ULPI tristate */
- null_phy_set_tristate(false);
-
- if (config->phy_restore_end)
- config->phy_restore_end();
-
- if (gpio_is_valid(config->phy_restore_gpio)) {
- int phy_restore_gpio = config->phy_restore_gpio;
- int retry = 20000;
-
- while (retry) {
- /* poll phy_restore_gpio high */
- if (gpio_get_value(phy_restore_gpio))
- break;
- retry--;
- }
-
- if (retry == 0)
- pr_info("phy_restore_gpio timeout\n");
- }
-
- /* enable ULPI CLK output pad */
- val = readl(base + ULPI_TIMING_CTRL_0);
- val |= ULPI_CLK_PADOUT_ENA;
- writel(val, base + ULPI_TIMING_CTRL_0);
-
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- udelay(5); /* wait for CLK stabilize */
-
- /* enable ULPI pinmux bypass */
- ulpi_pinmux_bypass(phy, true);
-#else
- /* enable ULPI pinmux bypass */
- ulpi_pinmux_bypass(phy, true);
- udelay(5);
-
- /* remove DIR tristate */
- tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DIR, TEGRA_TRI_NORMAL);
-#endif
+ return status;
}
-static int null_phy_power_on(struct tegra_usb_phy *phy, bool is_dpd)
+int tegra_usb_phy_power_off(struct tegra_usb_phy *phy)
{
- const struct tegra_ulpi_trimmer default_trimmer = {0, 0, 4, 4};
- unsigned long val;
- void __iomem *base = phy->regs;
- struct tegra_ulpi_config *config = phy->config;
- static bool cold_boot = true;
+ int err = 0;
- if (!config->trimmer)
- config->trimmer = &default_trimmer;
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
- ulpi_phy_reset(base);
+ if (!phy->phy_power_on)
+ return err;
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- /* remove ULPI PADS CLKEN reset */
- val = readl(base + USB_SUSP_CTRL);
- val &= ~ULPI_PADS_CLKEN_RESET;
- writel(val, base + USB_SUSP_CTRL);
- udelay(10);
-#endif
- val = readl(base + ULPI_TIMING_CTRL_0);
- val |= ULPI_OUTPUT_PINMUX_BYP | ULPI_CLKOUT_PINMUX_BYP;
- writel(val, base + ULPI_TIMING_CTRL_0);
-
- if (config->pre_phy_on && config->pre_phy_on())
- return -EAGAIN;
-
- val = readl(base + USB_SUSP_CTRL);
- val |= ULPI_PHY_ENABLE;
- writel(val, base + USB_SUSP_CTRL);
- udelay(10);
-
- /* set timming parameters */
- val = readl(base + ULPI_TIMING_CTRL_0);
- val |= ULPI_SHADOW_CLK_LOOPBACK_EN;
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- val &= ~ULPI_SHADOW_CLK_SEL;
- val &= ~ULPI_LBK_PAD_EN;
-#else
- val |= ULPI_SHADOW_CLK_SEL;
- val |= ULPI_LBK_PAD_EN;
-#endif
- val |= ULPI_SHADOW_CLK_DELAY(config->trimmer->shadow_clk_delay);
- val |= ULPI_CLOCK_OUT_DELAY(config->trimmer->clock_out_delay);
- val |= ULPI_LBK_PAD_E_INPUT_OR;
- writel(val, base + ULPI_TIMING_CTRL_0);
-
- writel(0, base + ULPI_TIMING_CTRL_1);
- udelay(10);
-
- /* start internal 60MHz clock */
- val = readl(base + ULPIS2S_CTRL);
- val |= ULPIS2S_ENA;
- val |= ULPIS2S_SUPPORT_DISCONNECT;
- val |= ULPIS2S_SPARE((phy->mode == TEGRA_USB_PHY_MODE_HOST) ? 3 : 1);
- val |= ULPIS2S_PLLU_MASTER_BLASTER60;
- writel(val, base + ULPIS2S_CTRL);
-
- /* select ULPI_CORE_CLK_SEL to SHADOW_CLK */
- val = readl(base + ULPI_TIMING_CTRL_0);
- val |= ULPI_CORE_CLK_SEL;
- writel(val, base + ULPI_TIMING_CTRL_0);
- udelay(10);
-
- /* enable ULPI null phy clock - can't set the trimmers before this */
- val = readl(base + ULPI_TIMING_CTRL_0);
- val |= ULPI_CLK_OUT_ENA;
- writel(val, base + ULPI_TIMING_CTRL_0);
- udelay(10);
-
- if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID,
- USB_PHY_CLK_VALID)) {
- pr_err("%s: timeout waiting for phy to stabilize\n", __func__);
- return -ETIMEDOUT;
+ if (phy->ops && phy->ops->power_off) {
+ if (phy->pdata->ops && phy->pdata->ops->pre_phy_off)
+ phy->pdata->ops->pre_phy_off();
+ err = phy->ops->power_off(phy);
+ if (phy->pdata->ops && phy->pdata->ops->post_phy_off)
+ phy->pdata->ops->post_phy_off();
}
- /* set ULPI trimmers */
- ulpi_set_trimmer(base, config->trimmer->data_trimmer,
- config->trimmer->stpdirnxt_trimmer, 1);
-
- ulpi_set_host(base);
-
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- /* remove slave0 reset */
- val = readl(base + USB_SUSP_CTRL);
- val &= ~ULPIS2S_SLV0_RESET;
- writel(val, base + USB_SUSP_CTRL);
-
- /* remove slave1 and line reset */
- val = readl(base + USB_SUSP_CTRL);
- val &= ~ULPIS2S_SLV1_RESET;
- val &= ~ULPIS2S_LINE_RESET;
-
- /* remove ULPI PADS reset */
- val &= ~ULPI_PADS_RESET;
- writel(val, base + USB_SUSP_CTRL);
-#endif
- if (cold_boot) {
- val = readl(base + ULPI_TIMING_CTRL_0);
- val |= ULPI_CLK_PADOUT_ENA;
- writel(val, base + ULPI_TIMING_CTRL_0);
- cold_boot = false;
+ clk_disable(phy->emc_clk);
+ clk_disable(phy->sys_clk);
+ if (phy->pdata->op_mode == TEGRA_USB_OPMODE_HOST) {
+ if (!phy->pdata->u_data.host.hot_plug &&
+ !phy->pdata->u_data.host.remote_wakeup_supported)
+ clk_disable(phy->ctrlr_clk);
+ } else {
+ /* In device mode clock is turned on by pmu irq handler
+ * if pmu irq is not available clocks will not be turned off/on
+ */
+ if (phy->pdata->u_data.dev.vbus_pmu_irq) {
+ clk_disable(phy->ctrlr_clk);
+ phy->ctrl_clk_on = false;
+ }
}
- udelay(10);
-
- if (config->post_phy_on && config->post_phy_on())
- return -EAGAIN;
-
- return 0;
-}
-
-static int null_phy_power_off(struct tegra_usb_phy *phy, bool is_dpd)
-{
- struct tegra_ulpi_config *config = phy->config;
-
- if (config->pre_phy_off && config->pre_phy_off())
- return -EAGAIN;
-
- null_phy_set_tristate(true);
-
- if (config->post_phy_off && config->post_phy_off())
- return -EAGAIN;
-
- return 0;
-}
-
-static int null_phy_pre_usbcmd_reset(struct tegra_usb_phy *phy, bool is_dpd)
-{
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- unsigned long val;
- void __iomem *base = phy->regs;
-
- val = readl(base + ULPIS2S_CTRL);
- val |= ULPIS2S_SLV0_CLAMP_XMIT;
- writel(val, base + ULPIS2S_CTRL);
-
- val = readl(base + USB_SUSP_CTRL);
- val |= ULPIS2S_SLV0_RESET;
- writel(val, base + USB_SUSP_CTRL);
- udelay(10);
-#endif
- return 0;
-}
-
-static int null_phy_post_usbcmd_reset(struct tegra_usb_phy *phy, bool is_dpd)
-{
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- unsigned long val;
- void __iomem *base = phy->regs;
-
- ulpi_set_host(base);
+ if (phy->vdd_reg && phy->vdd_reg_on)
+ if (phy->pdata->has_hostpc ||
+ phy->pdata->builtin_host_disabled) {
+ regulator_disable(phy->vdd_reg);
+ phy->vdd_reg_on = false;
+ }
- /* remove slave0 reset */
- val = readl(base + USB_SUSP_CTRL);
- val &= ~ULPIS2S_SLV0_RESET;
- writel(val, base + USB_SUSP_CTRL);
+ phy->phy_power_on = false;
- val = readl(base + ULPIS2S_CTRL);
- val &= ~ULPIS2S_SLV0_CLAMP_XMIT;
- writel(val, base + ULPIS2S_CTRL);
- udelay(10);
-#endif
- return 0;
+ return err;
}
-static int uhsic_phy_power_on(struct tegra_usb_phy *phy, bool is_dpd)
+int tegra_usb_phy_power_on(struct tegra_usb_phy *phy)
{
- unsigned long val;
- void __iomem *base = phy->regs;
- struct tegra_uhsic_config *uhsic_config = phy->config;
-
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- uhsic_powerup_pmc_wake_detect(phy);
-#endif
-
- if (uhsic_config->enable_gpio != -1) {
- gpio_set_value_cansleep(uhsic_config->enable_gpio, 1);
- /* keep hsic reset asserted for 1 ms */
- udelay(1000);
- }
-
- val = readl(base + UHSIC_PADS_CFG1);
- val &= ~(UHSIC_PD_BG | UHSIC_PD_TX | UHSIC_PD_TRK | UHSIC_PD_RX |
- UHSIC_PD_ZI | UHSIC_RPD_DATA | UHSIC_RPD_STROBE);
- val |= UHSIC_RX_SEL;
- writel(val, base + UHSIC_PADS_CFG1);
- udelay(2);
-
- val = readl(base + USB_SUSP_CTRL);
- val |= UHSIC_RESET;
- writel(val, base + USB_SUSP_CTRL);
- udelay(30);
-
- val = readl(base + USB_SUSP_CTRL);
- val |= UHSIC_PHY_ENABLE;
- writel(val, base + USB_SUSP_CTRL);
-
- val = readl(base + UHSIC_HSRX_CFG0);
- val |= UHSIC_IDLE_WAIT(uhsic_config->idle_wait_delay);
- val |= UHSIC_ELASTIC_UNDERRUN_LIMIT(uhsic_config->elastic_underrun_limit);
- val |= UHSIC_ELASTIC_OVERRUN_LIMIT(uhsic_config->elastic_overrun_limit);
- writel(val, base + UHSIC_HSRX_CFG0);
-
- val = readl(base + UHSIC_HSRX_CFG1);
- val |= UHSIC_HS_SYNC_START_DLY(uhsic_config->sync_start_delay);
- writel(val, base + UHSIC_HSRX_CFG1);
-
-#ifdef CONFIG_ARCH_TEGRA_3x_SOC
- /* WAR HSIC TX */
- val = readl(base + UHSIC_TX_CFG0);
- val &= ~UHSIC_HS_READY_WAIT_FOR_VALID;
- writel(val, base + UHSIC_TX_CFG0);
-#endif
-
- val = readl(base + UHSIC_MISC_CFG0);
- val |= UHSIC_SUSPEND_EXIT_ON_EDGE;
-#ifdef CONFIG_ARCH_TEGRA_3x_SOC
- /* Disable generic bus reset, to allow AP30 specific bus reset*/
- val |= UHSIC_DISABLE_BUSRESET;
-#endif
- writel(val, base + UHSIC_MISC_CFG0);
-
- val = readl(base + UHSIC_MISC_CFG1);
- val |= UHSIC_PLLU_STABLE_COUNT(phy->freq->stable_count);
- writel(val, base + UHSIC_MISC_CFG1);
-
- val = readl(base + UHSIC_PLL_CFG1);
- val |= UHSIC_PLLU_ENABLE_DLY_COUNT(phy->freq->enable_delay);
- val |= UHSIC_XTAL_FREQ_COUNT(phy->freq->xtal_freq_count);
- writel(val, base + UHSIC_PLL_CFG1);
+ int status = 0;
- val = readl(base + USB_SUSP_CTRL);
- val &= ~(UHSIC_RESET);
- writel(val, base + USB_SUSP_CTRL);
- udelay(2);
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- val = readl(base + USB_PORTSC1);
- val &= ~USB_PORTSC1_PTS(~0);
- writel(val, base + USB_PORTSC1);
+ if (phy->phy_power_on)
+ return status;
-#endif
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- val = readl(base + TEGRA_USB_USBMODE_REG_OFFSET);
- val |= TEGRA_USB_USBMODE_HOST;
- writel(val, base + TEGRA_USB_USBMODE_REG_OFFSET);
-
- /* Change the USB controller PHY type to HSIC */
- val = readl(base + HOSTPC1_DEVLC);
- val &= ~HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_MASK);
- val |= HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_HSIC);
- val &= ~HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_MASK);
- val |= HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_HIGH_SPEED);
- writel(val, base + HOSTPC1_DEVLC);
-#endif
- val = readl(base + USB_TXFILLTUNING);
- if ((val & USB_FIFO_TXFILL_MASK) != USB_FIFO_TXFILL_THRES(0x10)) {
- val = USB_FIFO_TXFILL_THRES(0x10);
- writel(val, base + USB_TXFILLTUNING);
+ if (phy->vdd_reg && !phy->vdd_reg_on) {
+ regulator_enable(phy->vdd_reg);
+ phy->vdd_reg_on = true;
}
- val = readl(base + USB_PORTSC1);
- val &= ~(USB_PORTSC1_WKOC | USB_PORTSC1_WKDS | USB_PORTSC1_WKCN);
- writel(val, base + USB_PORTSC1);
-
- val = readl(base + UHSIC_PADS_CFG0);
- val &= ~(UHSIC_TX_RTUNEN);
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- /* set Rtune impedance to 40 ohm */
- val |= UHSIC_TX_RTUNE(0);
-#else
- /* set Rtune impedance to 50 ohm */
- val |= UHSIC_TX_RTUNE(8);
-#endif
- writel(val, base + UHSIC_PADS_CFG0);
-
- if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID,
- USB_PHY_CLK_VALID)) {
- pr_err("%s: timeout waiting for phy to stabilize\n", __func__);
- return -ETIMEDOUT;
+ /* In device mode clock is turned on by pmu irq handler
+ * if pmu irq is not available clocks will not be turned off/on
+ */
+ if (phy->pdata->op_mode == TEGRA_USB_OPMODE_HOST) {
+ if (!phy->pdata->u_data.host.hot_plug &&
+ !phy->pdata->u_data.host.remote_wakeup_supported)
+ clk_enable(phy->ctrlr_clk);
+ } else {
+ if (phy->pdata->u_data.dev.vbus_pmu_irq &&
+ !phy->ctrl_clk_on) {
+ clk_enable(phy->ctrlr_clk);
+ phy->ctrl_clk_on = true;
+ }
}
+ clk_enable(phy->sys_clk);
+ clk_enable(phy->emc_clk);
- return 0;
-}
-
-static int uhsic_phy_power_off(struct tegra_usb_phy *phy, bool is_dpd)
-{
- unsigned long val;
- void __iomem *base = phy->regs;
- struct tegra_uhsic_config *uhsic_config = phy->config;
-
- val = readl(base + UHSIC_PADS_CFG1);
- val &= ~UHSIC_RPU_STROBE;
- val |= UHSIC_RPD_STROBE;
- writel(val, base + UHSIC_PADS_CFG1);
-
- val = readl(base + USB_SUSP_CTRL);
- val |= UHSIC_RESET;
- writel(val, base + USB_SUSP_CTRL);
- udelay(30);
-
- if (uhsic_config->enable_gpio != -1) {
- gpio_set_value_cansleep(uhsic_config->enable_gpio, 0);
- /* keep hsic reset de-asserted for 1 ms */
- udelay(1000);
+ if (phy->ops && phy->ops->power_on) {
+ if (phy->pdata->ops && phy->pdata->ops->pre_phy_on)
+ phy->pdata->ops->pre_phy_on();
+ status = phy->ops->power_on(phy);
+ if (phy->pdata->ops && phy->pdata->ops->post_phy_on)
+ phy->pdata->ops->post_phy_on();
}
- if (uhsic_config->post_phy_off && uhsic_config->post_phy_off())
- return -EAGAIN;
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- uhsic_powerdown_pmc_wake_detect(phy);
-#endif
+ phy->phy_power_on = true;
- return 0;
+ return status;
}
-#ifdef CONFIG_USB_TEGRA_OTG
-extern void tegra_otg_check_vbus_detection(void);
-#endif
-
-static irqreturn_t usb_phy_vbus_irq_thr(int irq, void *pdata)
+int tegra_usb_phy_reset(struct tegra_usb_phy *phy)
{
- struct tegra_usb_phy *phy = pdata;
-
- if (phy->reg_vdd && !phy->regulator_on) {
- regulator_enable(phy->reg_vdd);
- phy->regulator_on = 1;
- /*
- * Optimal time to get the regulator turned on
- * before detecting vbus interrupt.
- */
- mdelay(15);
- }
+ int status = 0;
-#ifdef CONFIG_USB_TEGRA_OTG
- tegra_otg_check_vbus_detection();
-#endif
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (phy->ops && phy->ops->reset)
+ status = phy->ops->reset(phy);
- return IRQ_HANDLED;
+ return status;
}
-
-struct tegra_usb_phy *tegra_usb_phy_open(int instance, void __iomem *regs,
- void *config, enum tegra_usb_phy_mode phy_mode,
- enum tegra_usb_phy_type usb_phy_type)
+int tegra_usb_phy_pre_suspend(struct tegra_usb_phy *phy)
{
- struct tegra_usb_phy *phy;
- struct tegra_ulpi_config *ulpi_config;
- unsigned long parent_rate;
- int i;
- int err;
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- struct tegra_uhsic_config *uhsic_config;
- int reset_gpio, enable_gpio;
-#endif
+ int status = 0;
- phy = kzalloc(sizeof(struct tegra_usb_phy), GFP_KERNEL);
- if (!phy)
- return ERR_PTR(-ENOMEM);
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
- phy->instance = instance;
- phy->regs = regs;
- phy->config = config;
- phy->mode = phy_mode;
- phy->usb_phy_type = usb_phy_type;
- phy->initialized = 0;
- phy->regulator_on = 0;
- phy->power_on = 0;
- phy->remote_wakeup = false;
- phy->hotplug = 0;
- phy->xcvr_setup_value = 0;
-
- if (!phy->config) {
- if (phy->usb_phy_type == TEGRA_USB_PHY_TYPE_LINK_ULPI ||
- phy->usb_phy_type == TEGRA_USB_PHY_TYPE_NULL_ULPI) {
- pr_err("%s: ulpi phy configuration missing", __func__);
- err = -EINVAL;
- goto err0;
- } else {
- phy->config = &utmip_default[instance];
- }
- }
+ if (phy->pdata->ops && phy->pdata->ops->pre_suspend)
+ phy->pdata->ops->pre_suspend();
- phy->pll_u = clk_get_sys(NULL, "pll_u");
- if (IS_ERR(phy->pll_u)) {
- pr_err("Can't get pll_u clock\n");
- err = PTR_ERR(phy->pll_u);
- goto err0;
- }
- clk_enable(phy->pll_u);
-
- parent_rate = clk_get_rate(clk_get_parent(phy->pll_u));
- if (phy->usb_phy_type == TEGRA_USB_PHY_TYPE_HSIC) {
- for (i = 0; i < ARRAY_SIZE(tegra_uhsic_freq_table); i++) {
- if (tegra_uhsic_freq_table[i].freq == parent_rate) {
- phy->freq = &tegra_uhsic_freq_table[i];
- break;
- }
- }
- } else {
- for (i = 0; i < ARRAY_SIZE(tegra_freq_table); i++) {
- if (tegra_freq_table[i].freq == parent_rate) {
- phy->freq = &tegra_freq_table[i];
- break;
- }
- }
- }
- if (!phy->freq) {
- pr_err("invalid pll_u parent rate %ld\n", parent_rate);
- err = -EINVAL;
- goto err1;
- }
-
- if (phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP) {
- err = utmip_pad_open(phy);
- phy->xcvr_setup_value = tegra_phy_xcvr_setup_value(phy->config);
- if (err < 0)
- goto err1;
- } else if (phy->usb_phy_type == TEGRA_USB_PHY_TYPE_LINK_ULPI) {
- ulpi_config = config;
-
- if (ulpi_config->clk) {
- phy->clk = clk_get_sys(NULL, ulpi_config->clk);
- if (IS_ERR(phy->clk)) {
- pr_err("%s: can't get ulpi clock\n", __func__);
- err = -ENXIO;
- goto err1;
- }
- } else {
- /* Some USB ULPI chips are not driven by Tegra clocks or PLL */
- phy->clk = NULL;
- }
- tegra_gpio_enable(ulpi_config->reset_gpio);
- gpio_request(ulpi_config->reset_gpio, "ulpi_phy_reset_b");
- gpio_direction_output(ulpi_config->reset_gpio, 0);
- phy->ulpi = otg_ulpi_create(&ulpi_viewport_access_ops, 0);
- phy->ulpi->io_priv = regs + ULPI_VIEWPORT;
- }
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- else if (phy->usb_phy_type == TEGRA_USB_PHY_TYPE_HSIC) {
- uhsic_config = config;
- enable_gpio = gpio_request(uhsic_config->enable_gpio,
- "uhsic_enable");
- reset_gpio = gpio_request(uhsic_config->reset_gpio,
- "uhsic_reset");
- /* hsic enable signal deasserted, hsic reset asserted */
- if (!enable_gpio)
- gpio_direction_output(uhsic_config->enable_gpio,
- 0 /* deasserted */);
- if (!reset_gpio)
- gpio_direction_output(uhsic_config->reset_gpio,
- 0 /* asserted */);
- if (!enable_gpio)
- tegra_gpio_enable(uhsic_config->enable_gpio);
- if (!reset_gpio)
- tegra_gpio_enable(uhsic_config->reset_gpio);
- /* keep hsic reset asserted for 1 ms */
- udelay(1000);
- /* enable (power on) hsic */
- if (!enable_gpio)
- gpio_set_value_cansleep(uhsic_config->enable_gpio, 1);
- udelay(1000);
- /* deassert reset */
- if (!reset_gpio)
- gpio_set_value_cansleep(uhsic_config->reset_gpio, 1);
- }
-#endif
-
- phy->reg_vdd = regulator_get(NULL, "avdd_usb");
- if (IS_ERR_OR_NULL(phy->reg_vdd)) {
- pr_err("couldn't get regulator avdd_usb: %ld \n",
- PTR_ERR(phy->reg_vdd));
- phy->reg_vdd = NULL;
- }
-
- if (instance == 0 && usb_phy_data[0].vbus_irq) {
- err = request_threaded_irq(usb_phy_data[0].vbus_irq, NULL, usb_phy_vbus_irq_thr, IRQF_SHARED,
- "usb_phy_vbus", phy);
- if (err) {
- pr_err("Failed to register IRQ\n");
- goto err1;
- }
- }
-
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- /* Power-up the VBUS detector for UTMIP PHY */
- if (phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP) {
- unsigned long val;
- void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
-
- /* turn on pad detectors for HSIC*/
- val = readl(pmc_base + PMC_USB_AO);
- val &= ~(TEGRA_PMC_USB_AO_VBUS_WAKEUP_PD_P0 | TEGRA_PMC_USB_AO_ID_PD_P0);
- writel(val, pmc_base + PMC_USB_AO);
-
- utmip_powerup_pmc_wake_detect(phy);
-
- if (usb_phy_data[phy->instance].vbus_reg_supply) {
- phy->reg_vbus = regulator_get(NULL, usb_phy_data[phy->instance].vbus_reg_supply);
- if (WARN_ON(IS_ERR_OR_NULL(phy->reg_vbus))) {
- pr_err("couldn't get regulator vdd_vbus_usb: %ld, instance : %d\n",
- PTR_ERR(phy->reg_vbus), phy->instance);
- err = PTR_ERR(phy->reg_vbus);
- goto err1;
- }
- }
- }
- if (phy->usb_phy_type == TEGRA_USB_PHY_TYPE_HSIC) {
- uhsic_powerup_pmc_wake_detect(phy);
- }
+ if (phy->ops && phy->ops->pre_suspend)
+ status = phy->ops->pre_suspend(phy);
-#endif
- if (((instance == 2) || (instance == 0)) &&
- (phy->mode == TEGRA_USB_PHY_MODE_HOST)) {
- vbus_enable(phy);
- }
- return phy;
-
-err1:
- clk_disable(phy->pll_u);
- clk_put(phy->pll_u);
-err0:
- kfree(phy);
- return ERR_PTR(err);
+ return status;
}
-EXPORT_SYMBOL_GPL(tegra_usb_phy_open);
-
-int tegra_usb_phy_power_on(struct tegra_usb_phy *phy, bool is_dpd)
+int tegra_usb_phy_suspend(struct tegra_usb_phy *phy)
{
- int ret = 0;
-
- const tegra_phy_fp power_on[] = {
- utmi_phy_power_on,
- ulpi_phy_power_on,
- null_phy_power_on,
- uhsic_phy_power_on,
- };
+ int err = 0;
- if (phy->power_on)
- return ret;
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
- if ((phy->instance == 0) && usb_phy_data[0].vbus_irq &&
- (phy->mode == TEGRA_USB_PHY_MODE_DEVICE))
- is_dpd = true;
+ if (phy->ops && phy->ops->suspend)
+ err = phy->ops->suspend(phy);
- if (phy->reg_vdd && !phy->regulator_on) {
- regulator_enable(phy->reg_vdd);
- phy->regulator_on = 1;
+ if (!err && phy->pdata->u_data.host.power_off_on_suspend) {
+ tegra_usb_phy_power_off(phy);
}
- if (power_on[phy->usb_phy_type])
- ret = power_on[phy->usb_phy_type](phy, is_dpd);
-
- phy->power_on = true;
- return ret;
+ return err;
}
-EXPORT_SYMBOL_GPL(tegra_usb_phy_power_on);
-
-void tegra_usb_phy_power_off(struct tegra_usb_phy *phy, bool is_dpd)
+int tegra_usb_phy_post_suspend(struct tegra_usb_phy *phy)
{
- const tegra_phy_fp power_off[] = {
- utmi_phy_power_off,
- ulpi_phy_power_off,
- null_phy_power_off,
- uhsic_phy_power_off,
- };
+ int status = 0;
- if (!phy->power_on)
- return;
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
- if ((phy->instance == 0) && usb_phy_data[0].vbus_irq &&
- (phy->mode == TEGRA_USB_PHY_MODE_DEVICE))
- is_dpd = true;
+ if (phy->ops && phy->ops->post_suspend)
+ status = phy->ops->post_suspend(phy);
- if (power_off[phy->usb_phy_type])
- power_off[phy->usb_phy_type](phy, is_dpd);
+ if (phy->pdata->ops && phy->pdata->ops->post_suspend)
+ phy->pdata->ops->post_suspend();
- if (phy->reg_vdd && phy->regulator_on && is_dpd) {
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- if (tegra_get_revision() >= TEGRA_REVISION_A03)
-#endif
- regulator_disable(phy->reg_vdd);
- phy->regulator_on = 0;
- }
- phy->power_on = false;
+ return status;
}
-EXPORT_SYMBOL_GPL(tegra_usb_phy_power_off);
-
-void tegra_usb_phy_preresume(struct tegra_usb_phy *phy, bool remote_wakeup)
+int tegra_usb_phy_pre_resume(struct tegra_usb_phy *phy, bool remote_wakeup)
{
- const tegra_phy_fp preresume[] = {
- utmi_phy_preresume,
- NULL,
- NULL,
- uhsic_phy_preresume,
- };
+ int status = 0;
- if (preresume[phy->usb_phy_type])
- preresume[phy->usb_phy_type](phy, remote_wakeup);
-}
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
-void tegra_usb_phy_postsuspend(struct tegra_usb_phy *phy, bool is_dpd)
+ if (phy->pdata->ops && phy->pdata->ops->pre_resume)
+ phy->pdata->ops->pre_resume();
-{
- const tegra_phy_fp postsuspend[] = {
- NULL,
- NULL,
- NULL,
- uhsic_phy_postsuspend,
- };
+ if (phy->ops && phy->ops->pre_resume)
+ status = phy->ops->pre_resume(phy, remote_wakeup);
- if (postsuspend[phy->usb_phy_type])
- postsuspend[phy->usb_phy_type](phy, is_dpd);
-}
-
-void tegra_usb_phy_postresume(struct tegra_usb_phy *phy, bool is_dpd)
-{
- const tegra_phy_fp postresume[] = {
- utmi_phy_postresume,
- NULL,
- NULL,
- uhsic_phy_postresume,
- };
-
- if (postresume[phy->usb_phy_type])
- postresume[phy->usb_phy_type](phy, is_dpd);
+ return status;
}
-
-void tegra_ehci_pre_reset(struct tegra_usb_phy *phy, bool is_dpd)
+int tegra_usb_phy_resume(struct tegra_usb_phy *phy)
{
- const tegra_phy_fp pre_reset[] = {
- NULL,
- NULL,
- null_phy_pre_usbcmd_reset,
- NULL,
- };
+ int err = 0;
- if (pre_reset[phy->usb_phy_type])
- pre_reset[phy->usb_phy_type](phy, is_dpd);
-}
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
-void tegra_ehci_post_reset(struct tegra_usb_phy *phy, bool is_dpd)
-{
- const tegra_phy_fp post_reset[] = {
- NULL,
- NULL,
- null_phy_post_usbcmd_reset,
- NULL,
- };
+ if (phy->pdata->u_data.host.power_off_on_suspend) {
+ tegra_usb_phy_power_on(phy);
+ }
- if (post_reset[phy->usb_phy_type])
- post_reset[phy->usb_phy_type](phy, is_dpd);
-}
+ if (!err && phy->ops && phy->ops->resume)
+ err = phy->ops->resume(phy);
-void tegra_ehci_phy_restore_start(struct tegra_usb_phy *phy,
- enum tegra_usb_phy_port_speed port_speed)
-{
- const tegra_phy_restore_start_fp phy_restore_start[] = {
- utmi_phy_restore_start,
- ulpi_phy_restore_start,
- null_phy_restore_start,
- NULL,
- };
+ return err;
- if (phy_restore_start[phy->usb_phy_type])
- phy_restore_start[phy->usb_phy_type](phy, port_speed);
}
-
-void tegra_ehci_phy_restore_end(struct tegra_usb_phy *phy)
+int tegra_usb_phy_post_resume(struct tegra_usb_phy *phy)
{
- const tegra_phy_restore_end_fp phy_restore_end[] = {
- utmi_phy_restore_end,
- ulpi_phy_restore_end,
- null_phy_restore_end,
- NULL,
- };
+ int status = 0;
- if (phy_restore_end[phy->usb_phy_type])
- phy_restore_end[phy->usb_phy_type](phy);
-}
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
-void tegra_usb_phy_clk_disable(struct tegra_usb_phy *phy)
-{
- if (phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP)
- utmi_phy_clk_disable(phy);
-}
+ if (phy->ops && phy->ops->post_resume)
+ status = phy->ops->post_resume(phy);
-void tegra_usb_phy_clk_enable(struct tegra_usb_phy *phy)
-{
- if (phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP)
- utmi_phy_clk_enable(phy);
-}
+ if (phy->pdata->ops && phy->pdata->ops->post_resume)
+ phy->pdata->ops->post_resume();
-void tegra_usb_phy_close(struct tegra_usb_phy *phy)
-{
- if (phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP) {
- utmip_pad_close(phy);
- utmip_phy_disable_pmc_bus_ctrl(phy);
- }
- else if (phy->usb_phy_type == TEGRA_USB_PHY_TYPE_LINK_ULPI && phy->clk)
- clk_put(phy->clk);
- if (phy->mode == TEGRA_USB_PHY_MODE_HOST) {
- vbus_disable(phy);
- }
- clk_disable(phy->pll_u);
- clk_put(phy->pll_u);
- if (phy->reg_vbus)
- regulator_put(phy->reg_vbus);
- if (phy->reg_vdd)
- regulator_put(phy->reg_vdd);
- if (phy->instance == 0 && usb_phy_data[0].vbus_irq)
- free_irq(usb_phy_data[0].vbus_irq, phy);
- kfree(phy);
+ return status;
}
-EXPORT_SYMBOL_GPL(tegra_usb_phy_close);
-
-int tegra_usb_phy_bus_connect(struct tegra_usb_phy *phy)
+int tegra_usb_phy_port_power(struct tegra_usb_phy *phy)
{
- unsigned long val;
- void __iomem *base = phy->regs;
- struct tegra_uhsic_config *uhsic_config = phy->config;
-
- if (phy->usb_phy_type == TEGRA_USB_PHY_TYPE_HSIC) {
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- val = readl(base + TEGRA_USB_USBMODE_REG_OFFSET);
- val |= TEGRA_USB_USBMODE_HOST;
- writel(val, base + TEGRA_USB_USBMODE_REG_OFFSET);
-
- /* Change the USB controller PHY type to HSIC */
- val = readl(base + HOSTPC1_DEVLC);
- val &= ~HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_MASK);
- val |= HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_HSIC);
- val &= ~HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_MASK);
- val |= HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_HIGH_SPEED);
- writel(val, base + HOSTPC1_DEVLC);
-#endif
- val = readl(base + UHSIC_MISC_CFG0);
- val |= UHSIC_DETECT_SHORT_CONNECT;
- writel(val, base + UHSIC_MISC_CFG0);
- udelay(1);
+ int status = 0;
- val = readl(base + UHSIC_MISC_CFG0);
- val |= UHSIC_FORCE_XCVR_MODE;
- writel(val, base + UHSIC_MISC_CFG0);
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
- val = readl(base + UHSIC_PADS_CFG1);
- val &= ~UHSIC_RPD_STROBE;
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- val |= UHSIC_RPU_STROBE;
-#endif
- writel(val, base + UHSIC_PADS_CFG1);
-
- if (uhsic_config->usb_phy_ready &&
- uhsic_config->usb_phy_ready())
- return -EAGAIN;
-
- /* connect detect on T30 requires extra wait */
- if (utmi_wait_register_timeout(base + UHSIC_STAT_CFG0,
- UHSIC_CONNECT_DETECT, UHSIC_CONNECT_DETECT,
- CONNECT_DETECT_TIMEOUT) < 0) {
- pr_err("%s: timeout waiting for hsic connect detect\n", __func__);
- return -ETIMEDOUT;
- }
+ if (phy->ops && phy->ops->port_power)
+ status = phy->ops->port_power(phy);
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- if (utmi_wait_register(base + USB_PORTSC1, USB_PORTSC1_LS(2), USB_PORTSC1_LS(2)) < 0) {
- pr_err("%s: timeout waiting for dplus state\n", __func__);
- return -ETIMEDOUT;
- }
-#endif
- }
-
- return 0;
+ return status;
}
-
int tegra_usb_phy_bus_reset(struct tegra_usb_phy *phy)
{
- unsigned long val;
- void __iomem *base = phy->regs;
-
- if (phy->usb_phy_type == TEGRA_USB_PHY_TYPE_HSIC) {
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- /* Change the USB controller PHY type to HSIC */
- val = readl(base + HOSTPC1_DEVLC);
- val &= ~HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_MASK);
- val |= HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_HSIC);
- val &= ~HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_MASK);
- val |= HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_HIGH_SPEED);
- writel(val, base + HOSTPC1_DEVLC);
- /* wait here, otherwise HOSTPC1_DEVLC_PSPD will timeout */
- mdelay(5);
-#endif
- val = readl(base + USB_PORTSC1);
- val |= USB_PORTSC1_PTC(5);
- writel(val, base + USB_PORTSC1);
- udelay(2);
-
- val = readl(base + USB_PORTSC1);
- val &= ~USB_PORTSC1_PTC(~0);
- writel(val, base + USB_PORTSC1);
- udelay(2);
-
- if (utmi_wait_register(base + USB_PORTSC1, USB_PORTSC1_LS(0), 0) < 0) {
- pr_err("%s: timeout waiting for SE0\n", __func__);
- return -ETIMEDOUT;
- }
+ int status = 0;
- if (utmi_wait_register(base + USB_PORTSC1, USB_PORTSC1_CCS, USB_PORTSC1_CCS) < 0) {
- pr_err("%s: timeout waiting for connection status\n", __func__);
- return -ETIMEDOUT;
- }
-
-#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
- if (utmi_wait_register(base + USB_PORTSC1, USB_PORTSC1_PSPD(2), USB_PORTSC1_PSPD(2)) < 0) {
- pr_err("%s: timeout waiting hsic high speed configuration\n", __func__);
- return -ETIMEDOUT;
- }
-#elif defined(CONFIG_ARCH_TEGRA_3x_SOC)
- if (utmi_wait_register(base + HOSTPC1_DEVLC,
- HOSTPC1_DEVLC_PSPD(2),
- HOSTPC1_DEVLC_PSPD(2)) < 0) {
- pr_err("%s: timeout waiting hsic high speed configuration\n", __func__);
- return -ETIMEDOUT;
- }
-#endif
- val = readl(base + USB_USBCMD);
- val &= ~USB_USBCMD_RS;
- writel(val, base + USB_USBCMD);
-
- if (utmi_wait_register(base + USB_USBSTS, USB_USBSTS_HCH, USB_USBSTS_HCH) < 0) {
- pr_err("%s: timeout waiting for stopping the controller\n", __func__);
- return -ETIMEDOUT;
- }
-
- val = readl(base + UHSIC_PADS_CFG1);
- val &= ~UHSIC_RPU_STROBE;
- val |= UHSIC_RPD_STROBE;
- writel(val, base + UHSIC_PADS_CFG1);
-
- mdelay(50);
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
- val = readl(base + UHSIC_PADS_CFG1);
- val &= ~UHSIC_RPD_STROBE;
- val |= UHSIC_RPU_STROBE;
- writel(val, base + UHSIC_PADS_CFG1);
+ if (phy->ops && phy->ops->bus_reset)
+ status = phy->ops->bus_reset(phy);
- val = readl(base + USB_USBCMD);
- val |= USB_USBCMD_RS;
- writel(val, base + USB_USBCMD);
-
- val = readl(base + UHSIC_PADS_CFG1);
- val &= ~UHSIC_RPU_STROBE;
- writel(val, base + UHSIC_PADS_CFG1);
-
- if (utmi_wait_register(base + USB_USBCMD, USB_USBCMD_RS, USB_USBCMD_RS) < 0) {
- pr_err("%s: timeout waiting for starting the controller\n", __func__);
- return -ETIMEDOUT;
- }
- }
-
- return 0;
+ return status;
}
-int tegra_usb_phy_bus_idle(struct tegra_usb_phy *phy)
+bool tegra_usb_phy_charger_detected(struct tegra_usb_phy *phy)
{
- unsigned long val;
- void __iomem *base = phy->regs;
- struct tegra_uhsic_config *uhsic_config = phy->config;
-
- if (phy->usb_phy_type == TEGRA_USB_PHY_TYPE_HSIC) {
-
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- val = readl(base + TEGRA_USB_USBMODE_REG_OFFSET);
- val |= TEGRA_USB_USBMODE_HOST;
- writel(val, base + TEGRA_USB_USBMODE_REG_OFFSET);
-
- /* Change the USB controller PHY type to HSIC */
- val = readl(base + HOSTPC1_DEVLC);
- val &= ~HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_MASK);
- val |= HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_HSIC);
- val &= ~HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_MASK);
- val |= HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_HIGH_SPEED);
- writel(val, base + HOSTPC1_DEVLC);
-#endif
- val = readl(base + UHSIC_MISC_CFG0);
- val |= UHSIC_DETECT_SHORT_CONNECT;
- writel(val, base + UHSIC_MISC_CFG0);
- udelay(1);
+ bool status = 0;
- val = readl(base + UHSIC_MISC_CFG0);
- val |= UHSIC_FORCE_XCVR_MODE;
- writel(val, base + UHSIC_MISC_CFG0);
-
- val = readl(base + UHSIC_PADS_CFG1);
- val &= ~UHSIC_RPD_STROBE;
- /* safe to enable RPU on STROBE at all times during idle */
- val |= UHSIC_RPU_STROBE;
- writel(val, base + UHSIC_PADS_CFG1);
-
- val = readl(base + USB_USBCMD);
- val &= ~USB_USBCMD_RS;
- writel(val, base + USB_USBCMD);
-
- if (uhsic_config->usb_phy_ready &&
- uhsic_config->usb_phy_ready())
- return -EAGAIN;
-
- /* connect detect on T30 requires extra wait */
- if (utmi_wait_register_timeout(base + UHSIC_STAT_CFG0,
- UHSIC_CONNECT_DETECT, UHSIC_CONNECT_DETECT,
- CONNECT_DETECT_TIMEOUT) < 0) {
- pr_err("%s: timeout waiting for hsic connect detect\n",
- __func__);
- return -ETIMEDOUT;
- }
- }
- return 0;
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (phy->ops && phy->ops->charger_detect)
+ status = phy->ops->charger_detect(phy);
+
+ return status;
}
-bool tegra_usb_phy_is_device_connected(struct tegra_usb_phy *phy)
+bool tegra_usb_phy_hw_accessible(struct tegra_usb_phy *phy)
{
- void __iomem *base = phy->regs;
+ if (!phy->hw_accessible)
+ DBG("%s(%d) inst:[%d] Not Accessible\n", __func__,
+ __LINE__, phy->inst);
- if (phy->usb_phy_type == TEGRA_USB_PHY_TYPE_HSIC) {
- if (utmi_wait_register(base + UHSIC_STAT_CFG0,
- UHSIC_CONNECT_DETECT, UHSIC_CONNECT_DETECT) < 0) {
- pr_err("%s: no hsic connection\n", __func__);
- return false;
- }
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- if (utmi_wait_register(base + USB_PORTSC1, USB_PORTSC1_LS(2), USB_PORTSC1_LS(2)) < 0) {
- pr_err("%s: timeout waiting for dplus state\n", __func__);
- return false;
- }
-#endif
- }
- return true;
+ return phy->hw_accessible;
}
-bool tegra_usb_phy_charger_detect(struct tegra_usb_phy *phy)
+bool tegra_usb_phy_remote_wakeup(struct tegra_usb_phy *phy)
{
- unsigned long val;
- void __iomem *base = phy->regs;
- bool status;
-
- if (phy->usb_phy_type != TEGRA_USB_PHY_TYPE_UTMIP)
- {
- /* Charger detection is not there for ULPI
- * return Charger not available */
- return false;
- }
-
- /* Enable charger detection logic */
- val = readl(base + UTMIP_BAT_CHRG_CFG0);
- val |= UTMIP_OP_SRC_EN | UTMIP_ON_SINK_EN;
- writel(val, base + UTMIP_BAT_CHRG_CFG0);
-
- /* Source should be on for 100 ms as per USB charging spec */
- msleep(TDP_SRC_ON_MS);
-
- val = readl(base + USB_PHY_VBUS_WAKEUP_ID);
- /* If charger is not connected disable the interrupt */
- val &= ~VDAT_DET_INT_EN;
- val |= VDAT_DET_CHG_DET;
- writel(val,base + USB_PHY_VBUS_WAKEUP_ID);
-
- val = readl(base + USB_PHY_VBUS_WAKEUP_ID);
- if (val & VDAT_DET_STS)
- status = true;
- else
- status = false;
-
- /* Disable charger detection logic */
- val = readl(base + UTMIP_BAT_CHRG_CFG0);
- val &= ~(UTMIP_OP_SRC_EN | UTMIP_ON_SINK_EN);
- writel(val, base + UTMIP_BAT_CHRG_CFG0);
-
- /* Delay of 40 ms before we pull the D+ as per battery charger spec */
- msleep(TDPSRC_CON_MS);
-
- return status;
+ return phy->remote_wakeup;
}
-EXPORT_SYMBOL_GPL(tegra_usb_phy_charger_detect);
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
-void tegra_usb_phy_power_down_pmc(void)
+bool tegra_usb_phy_has_hostpc(struct tegra_usb_phy *phy)
{
- unsigned long val;
- void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
-
- /* power down all 3 UTMIP interfaces */
- val = readl(pmc_base + PMC_UTMIP_MASTER_CONFIG);
- val |= UTMIP_PWR(0) | UTMIP_PWR(1) | UTMIP_PWR(2);
- writel(val, pmc_base + PMC_UTMIP_MASTER_CONFIG);
-
- /* turn on pad detectors */
- writel(PMC_POWER_DOWN_MASK, pmc_base + PMC_USB_AO);
-
- /* setup sleep walk fl all 3 usb controllers */
- val = UTMIP_USBOP_RPD_A | UTMIP_USBON_RPD_A | UTMIP_HIGHZ_A |
- UTMIP_USBOP_RPD_B | UTMIP_USBON_RPD_B | UTMIP_HIGHZ_B |
- UTMIP_USBOP_RPD_C | UTMIP_USBON_RPD_C | UTMIP_HIGHZ_C |
- UTMIP_USBOP_RPD_D | UTMIP_USBON_RPD_D | UTMIP_HIGHZ_D;
- writel(val, pmc_base + PMC_SLEEPWALK_REG(0));
- writel(val, pmc_base + PMC_SLEEPWALK_REG(1));
- writel(val, pmc_base + PMC_SLEEPWALK_REG(2));
-
- /* enable pull downs on HSIC PMC */
- val = UHSIC_STRB_RPD_A | UHSIC_DATA_RPD_A | UHSIC_STRB_RPD_B |
- UHSIC_DATA_RPD_B | UHSIC_STRB_RPD_C | UHSIC_DATA_RPD_C |
- UHSIC_STRB_RPD_D | UHSIC_DATA_RPD_D;
- writel(val, pmc_base + UHSIC_SLEEPWALK_REG);
-
- /* Turn over pad configuration to PMC */
- val = readl(pmc_base + PMC_SLEEP_CFG);
- val &= ~UTMIP_WAKE_VAL(0, ~0);
- val &= ~UTMIP_WAKE_VAL(1, ~0);
- val &= ~UTMIP_WAKE_VAL(2, ~0);
- val &= ~UHSIC_WAKE_VAL_P0(~0);
- val |= UTMIP_WAKE_VAL(0, WAKE_VAL_NONE) | UHSIC_WAKE_VAL_P0(WAKE_VAL_NONE) |
- UTMIP_WAKE_VAL(1, WAKE_VAL_NONE) | UTMIP_WAKE_VAL(2, WAKE_VAL_NONE) |
- UTMIP_RCTRL_USE_PMC(0) | UTMIP_RCTRL_USE_PMC(1) | UTMIP_RCTRL_USE_PMC(2) |
- UTMIP_TCTRL_USE_PMC(0) | UTMIP_TCTRL_USE_PMC(1) | UTMIP_TCTRL_USE_PMC(2) |
- UTMIP_FSLS_USE_PMC(0) | UTMIP_FSLS_USE_PMC(1) | UTMIP_FSLS_USE_PMC(2) |
- UTMIP_MASTER_ENABLE(0) | UTMIP_MASTER_ENABLE(1) | UTMIP_MASTER_ENABLE(2) |
- UHSIC_MASTER_ENABLE_P0;
- writel(val, pmc_base + PMC_SLEEP_CFG);
+ return phy->pdata->has_hostpc;
}
-#endif
-int __init tegra_usb_phy_init(struct usb_phy_plat_data *pdata, int size)
+bool tegra_usb_phy_otg_supported(struct tegra_usb_phy *phy)
{
- if (pdata) {
- int i;
-
- for (i = 0; i < size; i++, pdata++) {
- usb_phy_data[pdata->instance].instance = pdata->instance;
- usb_phy_data[pdata->instance].vbus_irq = pdata->vbus_irq;
- usb_phy_data[pdata->instance].vbus_gpio = pdata->vbus_gpio;
- usb_phy_data[pdata->instance].vbus_gpio_inverted = pdata->vbus_gpio_inverted;
- usb_phy_data[pdata->instance].vbus_reg_supply = pdata->vbus_reg_supply;
- }
- }
-
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- tegra_usb_phy_power_down_pmc();
-#endif
-
- return 0;
+ return phy->pdata->port_otg;
}
void tegra_usb_phy_memory_prefetch_on(struct tegra_usb_phy *phy)
@@ -3226,7 +699,7 @@ void tegra_usb_phy_memory_prefetch_on(struct tegra_usb_phy *phy)
void __iomem *ahb_gizmo = IO_ADDRESS(TEGRA_AHB_GIZMO_BASE);
unsigned long val;
- if (phy->instance == 0 && phy->mode == TEGRA_USB_PHY_MODE_DEVICE) {
+ if (phy->inst == 0 && phy->pdata->op_mode == TEGRA_USB_OPMODE_DEVICE) {
val = readl(ahb_gizmo + AHB_MEM_PREFETCH_CFG1);
val |= PREFETCH_ENB;
writel(val, ahb_gizmo + AHB_MEM_PREFETCH_CFG1);
@@ -3235,14 +708,13 @@ void tegra_usb_phy_memory_prefetch_on(struct tegra_usb_phy *phy)
writel(val, ahb_gizmo + AHB_MEM_PREFETCH_CFG2);
}
}
-EXPORT_SYMBOL_GPL(tegra_usb_phy_memory_prefetch_on);
void tegra_usb_phy_memory_prefetch_off(struct tegra_usb_phy *phy)
{
void __iomem *ahb_gizmo = IO_ADDRESS(TEGRA_AHB_GIZMO_BASE);
unsigned long val;
- if (phy->instance == 0 && phy->mode == TEGRA_USB_PHY_MODE_DEVICE) {
+ if (phy->inst == 0 && phy->pdata->op_mode == TEGRA_USB_OPMODE_DEVICE) {
val = readl(ahb_gizmo + AHB_MEM_PREFETCH_CFG1);
val &= ~(PREFETCH_ENB);
writel(val, ahb_gizmo + AHB_MEM_PREFETCH_CFG1);
@@ -3251,39 +723,3 @@ void tegra_usb_phy_memory_prefetch_off(struct tegra_usb_phy *phy)
writel(val, ahb_gizmo + AHB_MEM_PREFETCH_CFG2);
}
}
-EXPORT_SYMBOL_GPL(tegra_usb_phy_memory_prefetch_off);
-
-/* disable walk and wake events after resume from LP0 */
-bool tegra_usb_phy_is_remotewake_detected(struct tegra_usb_phy *phy)
-{
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
- void __iomem *base = phy->regs;
- unsigned int inst = phy->instance;
- u32 val;
-
- val = readl(base + UTMIP_PMC_WAKEUP0);
- if (val & EVENT_INT_ENB) {
- val = readl(pmc_base + UTMIP_UHSIC_STATUS);
- if (UTMIP_WAKE_ALARM(inst) & val) {
- val = readl(pmc_base + PMC_SLEEP_CFG);
- val &= ~UTMIP_WAKE_VAL(inst, 0x0);
- val |= UTMIP_WAKE_VAL(inst, WAKE_VAL_NONE);
- writel(val, pmc_base + PMC_SLEEP_CFG);
-
- val = readl(pmc_base + PMC_TRIGGERS);
- val |= UTMIP_CLR_WAKE_ALARM(inst) |
- UTMIP_CLR_WALK_PTR(inst);
- writel(val, pmc_base + PMC_TRIGGERS);
-
- val = readl(base + UTMIP_PMC_WAKEUP0);
- val &= ~EVENT_INT_ENB;
- writel(val, base + UTMIP_PMC_WAKEUP0);
- phy->remote_wakeup = true;
- return true;
- }
- }
-#endif
- return false;
-}
-
diff --git a/arch/arm/mach-tegra/wakeups-t2.c b/arch/arm/mach-tegra/wakeups-t2.c
index 7c5d12ac60d4..adfe136c8118 100644
--- a/arch/arm/mach-tegra/wakeups-t2.c
+++ b/arch/arm/mach-tegra/wakeups-t2.c
@@ -22,90 +22,42 @@
#include <mach/gpio.h>
#include "gpio-names.h"
-
-static int tegra_wake_event_irq[] = {
- [0] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PO5),
- [1] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV3),
- [2] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PL1),
- [3] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PB6),
- [4] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PN7),
- [5] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PA0),
- [6] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PU5),
- [7] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PU6),
- [8] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PC7),
- [9] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS2),
- [10] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PAA1),
- [11] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PW3),
- [12] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PW2),
- [13] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PY6),
- [14] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV6),
- [15] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PJ7),
- [16] = INT_RTC,
- [17] = INT_KBC,
- [18] = INT_EXTERNAL_PMU,
- [19] = -EINVAL, /* TEGRA_USB1_VBUS, */
- [20] = -EINVAL, /* TEGRA_USB3_VBUS, */
- [21] = -EINVAL, /* TEGRA_USB1_ID, */
- [22] = -EINVAL, /* TEGRA_USB3_ID, */
- [23] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PI5),
- [24] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV2),
- [25] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS4),
- [26] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS5),
- [27] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS0),
- [28] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PQ6),
- [29] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PQ7),
- [30] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PN2),
+#include "wakeups.h"
+
+static struct tegra_wake_info tegra_wake_event_data_t2[] = {
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PO5), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV3), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PL1), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PB6), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PN7), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PA0), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PU5), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PU6), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PC7), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS2), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PAA1), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PW3), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PW2), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PY6), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV6), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PJ7), POLARITY_NONE},
+ {INT_RTC, POLARITY_NONE},
+ {INT_KBC, POLARITY_NONE},
+ {INT_EXTERNAL_PMU, POLARITY_NONE},
+ {INT_USB, POLARITY_EDGE_ANY}, /* TEGRA_USB1_VBUS, */
+ {-EINVAL, POLARITY_EDGE_ANY}, /* TEGRA_USB3_VBUS, */
+ {-EINVAL, POLARITY_EDGE_ANY}, /* TEGRA_USB1_ID, */
+ {-EINVAL, POLARITY_EDGE_ANY}, /* TEGRA_USB3_ID, */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PI5), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV2), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS4), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS5), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS0), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PQ6), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PQ7), POLARITY_NONE},
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PN2), POLARITY_NONE},
};
-int tegra_irq_to_wake(int irq)
-{
- int i;
- int wake_irq;
- int search_gpio;
- static int last_wake = -1;
-
- /* Two level wake irq search for gpio based wakeups -
- * 1. check for GPIO irq(based on tegra_wake_event_irq table)
- * e.g. for a board, wake7 based on GPIO PU6 and irq==358 done first
- * 2. check for gpio bank irq assuming search for GPIO irq
- * preceded this search.
- * e.g. in this step check for gpio bank irq GPIO6 irq==119
- */
- for (i = 0; i < ARRAY_SIZE(tegra_wake_event_irq); i++) {
- /* return if step 1 matches */
- if (tegra_wake_event_irq[i] == irq) {
- pr_info("Wake%d for irq=%d\n", i, irq);
- last_wake = i;
- return i;
- }
-
- /* step 2 below uses saved last_wake from step 1
- * in previous call */
- search_gpio = irq_to_gpio(
- tegra_wake_event_irq[i]);
- if (search_gpio < 0)
- continue;
- wake_irq = tegra_gpio_get_bank_int_nr(search_gpio);
- if (wake_irq < 0)
- continue;
- if ((last_wake == i) &&
- (wake_irq == irq)) {
- pr_info("gpio bank wake found: wake%d for irq=%d\n",
- i, irq);
- return i;
- }
- }
-
- return -EINVAL;
-}
-
-int tegra_wake_to_irq(int wake)
-{
- if (wake < 0)
- return -EINVAL;
-
- if (wake >= ARRAY_SIZE(tegra_wake_event_irq))
- return -EINVAL;
+struct tegra_wake_info *tegra_wake_event_data = tegra_wake_event_data_t2;
+unsigned int tegra_wake_event_data_size = ARRAY_SIZE(tegra_wake_event_data_t2);
- return tegra_wake_event_irq[wake];
-}
diff --git a/arch/arm/mach-tegra/wakeups-t2.h b/arch/arm/mach-tegra/wakeups-t2.h
index eb193c0aaf9e..955b351a71fa 100644
--- a/arch/arm/mach-tegra/wakeups-t2.h
+++ b/arch/arm/mach-tegra/wakeups-t2.h
@@ -30,36 +30,36 @@
int tegra_irq_to_wake(int irq);
int tegra_wake_to_irq(int wake);
-#define TEGRA_WAKE_GPIO_PO5 (1 << 0)
-#define TEGRA_WAKE_GPIO_PV3 (1 << 1)
-#define TEGRA_WAKE_GPIO_PL1 (1 << 2)
-#define TEGRA_WAKE_GPIO_PB6 (1 << 3)
-#define TEGRA_WAKE_GPIO_PN7 (1 << 4)
-#define TEGRA_WAKE_GPIO_PA0 (1 << 5)
-#define TEGRA_WAKE_GPIO_PU5 (1 << 6)
-#define TEGRA_WAKE_GPIO_PU6 (1 << 7)
-#define TEGRA_WAKE_GPIO_PC7 (1 << 8)
-#define TEGRA_WAKE_GPIO_PS2 (1 << 9)
-#define TEGRA_WAKE_GPIO_PAA1 (1 << 10)
-#define TEGRA_WAKE_GPIO_PW3 (1 << 11)
-#define TEGRA_WAKE_GPIO_PW2 (1 << 12)
-#define TEGRA_WAKE_GPIO_PY6 (1 << 13)
-#define TEGRA_WAKE_GPIO_PV6 (1 << 14)
-#define TEGRA_WAKE_GPIO_PJ7 (1 << 15)
-#define TEGRA_WAKE_RTC_ALARM (1 << 16)
-#define TEGRA_WAKE_KBC_EVENT (1 << 17)
-#define TEGRA_WAKE_PWR_INT (1 << 18)
-#define TEGRA_WAKE_USB1_VBUS (1 << 19)
-#define TEGRA_WAKE_USB3_VBUS (1 << 20)
-#define TEGRA_WAKE_USB1_ID (1 << 21)
-#define TEGRA_WAKE_USB3_ID (1 << 22)
-#define TEGRA_WAKE_GPIO_PI5 (1 << 23)
-#define TEGRA_WAKE_GPIO_PV2 (1 << 24)
-#define TEGRA_WAKE_GPIO_PS4 (1 << 25)
-#define TEGRA_WAKE_GPIO_PS5 (1 << 26)
-#define TEGRA_WAKE_GPIO_PS0 (1 << 27)
-#define TEGRA_WAKE_GPIO_PQ6 (1 << 28)
-#define TEGRA_WAKE_GPIO_PQ7 (1 << 29)
-#define TEGRA_WAKE_GPIO_PN2 (1 << 30)
+#define TEGRA_WAKE_GPIO_PO5 0
+#define TEGRA_WAKE_GPIO_PV3 1
+#define TEGRA_WAKE_GPIO_PL1 2
+#define TEGRA_WAKE_GPIO_PB6 3
+#define TEGRA_WAKE_GPIO_PN7 4
+#define TEGRA_WAKE_GPIO_PA0 5
+#define TEGRA_WAKE_GPIO_PU5 6
+#define TEGRA_WAKE_GPIO_PU6 7
+#define TEGRA_WAKE_GPIO_PC7 8
+#define TEGRA_WAKE_GPIO_PS2 9
+#define TEGRA_WAKE_GPIO_PAA1 10
+#define TEGRA_WAKE_GPIO_PW3 11
+#define TEGRA_WAKE_GPIO_PW2 12
+#define TEGRA_WAKE_GPIO_PY6 13
+#define TEGRA_WAKE_GPIO_PV6 14
+#define TEGRA_WAKE_GPIO_PJ7 15
+#define TEGRA_WAKE_RTC_ALARM 16
+#define TEGRA_WAKE_KBC_EVENT 17
+#define TEGRA_WAKE_PWR_INT 18
+#define TEGRA_WAKE_USB1_VBUS 19
+#define TEGRA_WAKE_USB3_VBUS 20
+#define TEGRA_WAKE_USB1_ID 21
+#define TEGRA_WAKE_USB3_ID 22
+#define TEGRA_WAKE_GPIO_PI5 23
+#define TEGRA_WAKE_GPIO_PV2 24
+#define TEGRA_WAKE_GPIO_PS4 25
+#define TEGRA_WAKE_GPIO_PS5 26
+#define TEGRA_WAKE_GPIO_PS0 27
+#define TEGRA_WAKE_GPIO_PQ6 28
+#define TEGRA_WAKE_GPIO_PQ7 29
+#define TEGRA_WAKE_GPIO_PN2 30
#endif
diff --git a/arch/arm/mach-tegra/wakeups-t3.c b/arch/arm/mach-tegra/wakeups-t3.c
index 823736204362..ef471cb035db 100644
--- a/arch/arm/mach-tegra/wakeups-t3.c
+++ b/arch/arm/mach-tegra/wakeups-t3.c
@@ -22,101 +22,53 @@
#include <mach/gpio.h>
#include "gpio-names.h"
+#include "wakeups.h"
-static int tegra_wake_event_irq[] = {
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PO5), /* wake0 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV1), /* wake1 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PL1), /* wake2 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PB6), /* wake3 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PN7), /* wake4 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PBB6), /* wake5 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PU5), /* wake6 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PU6), /* wake7 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PC7), /* wake8 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS2), /* wake9 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PAA1), /* wake10 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PW3), /* wake11 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PW2), /* wake12 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PY6), /* wake13 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PDD3), /* wake14 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PJ2), /* wake15 */
- INT_RTC, /* wake16 */
- INT_KBC, /* wake17 */
- INT_EXTERNAL_PMU, /* wake18 */
- -EINVAL, /* TEGRA_USB1_VBUS, */ /* wake19 */
- -EINVAL, /* TEGRA_USB2_VBUS, */ /* wake20 */
- -EINVAL, /* TEGRA_USB1_ID, */ /* wake21 */
- -EINVAL, /* TEGRA_USB2_ID, */ /* wake22 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PI5), /* wake23 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV0), /* wake24 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS4), /* wake25 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS5), /* wake26 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS0), /* wake27 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS6), /* wake28 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS7), /* wake29 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PN2), /* wake30 */
- -EINVAL, /* not used */ /* wake31 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PO4), /* wake32 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PJ0), /* wake33 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PK2), /* wake34 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PI6), /* wake35 */
- TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PBB1), /* wake36 */
- -EINVAL, /* TEGRA_USB3_VBUS, */ /* wake37 */
- -EINVAL, /* TEGRA_USB3_ID, */ /* wake38 */
- INT_USB, /* TEGRA_USB1_UTMIP, */ /* wake39 */
- INT_USB2, /* TEGRA_USB2_UTMIP, */ /* wake40 */
- INT_USB3, /* TEGRA_USB3_UTMIP, */ /* wake41 */
+static struct tegra_wake_info tegra_wake_event_data_t3[] = {
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PO5), POLARITY_NONE}, /* wake0 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV1), POLARITY_NONE}, /* wake1 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PL1), POLARITY_NONE}, /* wake2 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PB6), POLARITY_NONE}, /* wake3 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PN7), POLARITY_NONE}, /* wake4 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PBB6), POLARITY_NONE}, /* wake5 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PU5), POLARITY_NONE}, /* wake6 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PU6), POLARITY_NONE}, /* wake7 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PC7), POLARITY_NONE}, /* wake8 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS2), POLARITY_NONE}, /* wake9 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PAA1), POLARITY_NONE}, /* wake10 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PW3), POLARITY_NONE}, /* wake11 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PW2), POLARITY_NONE}, /* wake12 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PY6), POLARITY_NONE}, /* wake13 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PDD3), POLARITY_NONE}, /* wake14 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PJ2), POLARITY_NONE}, /* wake15 */
+ {INT_RTC, POLARITY_NONE}, /* wake16 */
+ {INT_KBC, POLARITY_NONE}, /* wake17 */
+ {INT_EXTERNAL_PMU, POLARITY_NONE}, /* wake18 */
+ {INT_USB, POLARITY_EDGE_ANY}, /* TEGRA_USB1_VBUS, */ /* wake19 */
+ {-EINVAL, POLARITY_EDGE_ANY}, /* TEGRA_USB2_VBUS, */ /* wake20 */
+ {INT_USB, POLARITY_EDGE_ANY}, /* TEGRA_USB1_ID, */ /* wake21 */
+ {-EINVAL, POLARITY_EDGE_ANY}, /* TEGRA_USB2_ID, */ /* wake22 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PI5), POLARITY_NONE}, /* wake23 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV0), POLARITY_NONE}, /* wake24 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS4), POLARITY_NONE}, /* wake25 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS5), POLARITY_NONE}, /* wake26 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS0), POLARITY_NONE}, /* wake27 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS6), POLARITY_NONE}, /* wake28 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS7), POLARITY_NONE}, /* wake29 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PN2), POLARITY_NONE}, /* wake30 */
+ {-EINVAL, POLARITY_NONE}, /* not used */ /* wake31 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PO4), POLARITY_NONE}, /* wake32 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PJ0), POLARITY_NONE}, /* wake33 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PK2), POLARITY_NONE}, /* wake34 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PI6), POLARITY_NONE}, /* wake35 */
+ {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PBB1), POLARITY_NONE}, /* wake36 */
+ {-EINVAL, POLARITY_NONE}, /* TEGRA_USB3_VBUS, */ /* wake37 */
+ {-EINVAL, POLARITY_NONE}, /* TEGRA_USB3_ID, */ /* wake38 */
+ {INT_USB, POLARITY_LEVEL_HI}, /* TEGRA_USB1_UTMIP, */ /* wake39 */
+ {INT_USB2, POLARITY_LEVEL_HI}, /* TEGRA_USB2_UTMIP, */ /* wake40 */
+ {INT_USB3, POLARITY_LEVEL_HI} /* TEGRA_USB3_UTMIP, */ /* wake41 */
};
-int tegra_irq_to_wake(int irq)
-{
- int i;
- int wake_irq;
- int search_gpio;
- static int last_wake = -1;
+struct tegra_wake_info *tegra_wake_event_data = tegra_wake_event_data_t3;
+unsigned int tegra_wake_event_data_size = ARRAY_SIZE(tegra_wake_event_data_t3);
- /* Two level wake irq search for gpio based wakeups -
- * 1. check for GPIO irq(based on tegra_wake_event_irq table)
- * e.g. for a board, wake7 based on GPIO PU6 and irq==390 done first
- * 2. check for gpio bank irq assuming search for GPIO irq
- * preceded this search.
- * e.g. in this step check for gpio bank irq GPIO6 irq==119
- */
- for (i = 0; i < ARRAY_SIZE(tegra_wake_event_irq); i++) {
- /* return if step 1 matches */
- if (tegra_wake_event_irq[i] == irq) {
- pr_info("Wake%d for irq=%d\n", i, irq);
- last_wake = i;
- return i;
- }
-
- /* step 2 below uses saved last_wake from step 1
- * in previous call */
- search_gpio = irq_to_gpio(
- tegra_wake_event_irq[i]);
- if (search_gpio < 0)
- continue;
- wake_irq = tegra_gpio_get_bank_int_nr(search_gpio);
- if (wake_irq < 0)
- continue;
- if ((last_wake == i) &&
- (wake_irq == irq)) {
- pr_info("gpio bank wake found: wake%d for irq=%d\n",
- i, irq);
- return i;
- }
- }
-
- return -EINVAL;
-}
-
-int tegra_wake_to_irq(int wake)
-{
- if (wake < 0)
- return -EINVAL;
-
- if (wake >= ARRAY_SIZE(tegra_wake_event_irq))
- return -EINVAL;
-
- return tegra_wake_event_irq[wake];
-}
diff --git a/arch/arm/mach-tegra/wakeups-t3.h b/arch/arm/mach-tegra/wakeups-t3.h
index f811d8939387..6c051270cc93 100644
--- a/arch/arm/mach-tegra/wakeups-t3.h
+++ b/arch/arm/mach-tegra/wakeups-t3.h
@@ -27,45 +27,45 @@
#error "Tegra 3 wakeup sources valid only for CONFIG_ARCH_TEGRA_3x_SOC"
#endif
-#define TEGRA_WAKE_GPIO_PO5 (1ull << 0)
-#define TEGRA_WAKE_GPIO_PV1 (1ull << 1)
-#define TEGRA_WAKE_GPIO_PL1 (1ull << 2)
-#define TEGRA_WAKE_GPIO_PB6 (1ull << 3)
-#define TEGRA_WAKE_GPIO_PN7 (1ull << 4)
-#define TEGRA_WAKE_GPIO_PBB6 (1ull << 5)
-#define TEGRA_WAKE_GPIO_PU5 (1ull << 6)
-#define TEGRA_WAKE_GPIO_PU6 (1ull << 7)
-#define TEGRA_WAKE_GPIO_PC7 (1ull << 8)
-#define TEGRA_WAKE_GPIO_PS2 (1ull << 9)
-#define TEGRA_WAKE_GPIO_PAA1 (1ull << 10)
-#define TEGRA_WAKE_GPIO_PW3 (1ull << 11)
-#define TEGRA_WAKE_GPIO_PW2 (1ull << 12)
-#define TEGRA_WAKE_GPIO_PY6 (1ull << 13)
-#define TEGRA_WAKE_GPIO_PDD3 (1ull << 14)
-#define TEGRA_WAKE_GPIO_PJ2 (1ull << 15)
-#define TEGRA_WAKE_RTC_ALARM (1ull << 16)
-#define TEGRA_WAKE_KBC_EVENT (1ull << 17)
-#define TEGRA_WAKE_PWR_INT (1ull << 18)
-#define TEGRA_WAKE_USB1_VBUS (1ull << 19)
-#define TEGRA_WAKE_USB2_VBUS (1ull << 20)
-#define TEGRA_WAKE_USB1_ID (1ull << 21)
-#define TEGRA_WAKE_USB2_ID (1ull << 22)
-#define TEGRA_WAKE_GPIO_PI5 (1ull << 23)
-#define TEGRA_WAKE_GPIO_PV0 (1ull << 24)
-#define TEGRA_WAKE_GPIO_PS4 (1ull << 25)
-#define TEGRA_WAKE_GPIO_PS5 (1ull << 26)
-#define TEGRA_WAKE_GPIO_PS0 (1ull << 27)
-#define TEGRA_WAKE_GPIO_PS6 (1ull << 28)
-#define TEGRA_WAKE_GPIO_PS7 (1ull << 29)
-#define TEGRA_WAKE_GPIO_PN2 (1ull << 30)
+#define TEGRA_WAKE_GPIO_PO5 0
+#define TEGRA_WAKE_GPIO_PV1 1
+#define TEGRA_WAKE_GPIO_PL1 2
+#define TEGRA_WAKE_GPIO_PB6 3
+#define TEGRA_WAKE_GPIO_PN7 4
+#define TEGRA_WAKE_GPIO_PBB6 5
+#define TEGRA_WAKE_GPIO_PU5 6
+#define TEGRA_WAKE_GPIO_PU6 7
+#define TEGRA_WAKE_GPIO_PC7 8
+#define TEGRA_WAKE_GPIO_PS2 9
+#define TEGRA_WAKE_GPIO_PAA1 10
+#define TEGRA_WAKE_GPIO_PW3 11
+#define TEGRA_WAKE_GPIO_PW2 12
+#define TEGRA_WAKE_GPIO_PY6 13
+#define TEGRA_WAKE_GPIO_PDD3 14
+#define TEGRA_WAKE_GPIO_PJ2 15
+#define TEGRA_WAKE_RTC_ALARM 16
+#define TEGRA_WAKE_KBC_EVENT 17
+#define TEGRA_WAKE_PWR_INT 18
+#define TEGRA_WAKE_USB1_VBUS 19
+#define TEGRA_WAKE_USB2_VBUS 20
+#define TEGRA_WAKE_USB1_ID 21
+#define TEGRA_WAKE_USB2_ID 22
+#define TEGRA_WAKE_GPIO_PI5 23
+#define TEGRA_WAKE_GPIO_PV0 24
+#define TEGRA_WAKE_GPIO_PS4 25
+#define TEGRA_WAKE_GPIO_PS5 26
+#define TEGRA_WAKE_GPIO_PS0 27
+#define TEGRA_WAKE_GPIO_PS6 28
+#define TEGRA_WAKE_GPIO_PS7 29
+#define TEGRA_WAKE_GPIO_PN2 30
/* bit 31 is unused */
-#define TEGRA_WAKE_GPIO_PO4 (1ull << 32)
-#define TEGRA_WAKE_GPIO_PJ0 (1ull << 33)
-#define TEGRA_WAKE_GPIO_PK2 (1ull << 34)
-#define TEGRA_WAKE_GPIO_PI6 (1ull << 35)
-#define TEGRA_WAKE_GPIO_PBB1 (1ull << 36)
-#define TEGRA_WAKE_USB3_ID (1ull << 37)
-#define TEGRA_WAKE_USB3_VBUS (1ull << 38)
+#define TEGRA_WAKE_GPIO_PO4 32
+#define TEGRA_WAKE_GPIO_PJ0 33
+#define TEGRA_WAKE_GPIO_PK2 34
+#define TEGRA_WAKE_GPIO_PI6 35
+#define TEGRA_WAKE_GPIO_PBB1 36
+#define TEGRA_WAKE_USB3_ID 37
+#define TEGRA_WAKE_USB3_VBUS 38
#endif
diff --git a/arch/arm/mach-tegra/wakeups.c b/arch/arm/mach-tegra/wakeups.c
new file mode 100644
index 000000000000..a52a4d50c074
--- /dev/null
+++ b/arch/arm/mach-tegra/wakeups.c
@@ -0,0 +1,130 @@
+/*
+ * 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/kernel.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+
+#include <mach/iomap.h>
+#include <mach/irqs.h>
+#include <mach/gpio.h>
+
+#include "gpio-names.h"
+#include "wakeups.h"
+
+extern struct tegra_wake_info *tegra_wake_event_data;
+extern unsigned int tegra_wake_event_data_size;
+
+/*
+ * FIXME: unable to pass rising and falling
+ * flags from usb driver hence using polarity field
+ * from wake table to set wake_mask_any
+ * for selected usb wake sources - VBUS and ID
+ */
+static int update_wake_mask(unsigned int index, int flow_type,
+ struct wake_mask_types *wake_msk)
+{
+ int trigger_val;
+ /*
+ * set wake function calls with flow_type as -1
+ * set wake type function calls update_wake_mask with
+ * the wake polarity
+ */
+ if (flow_type == -1) {
+ pr_debug("Wake%d flow_type=%d\n",
+ index, flow_type);
+ /* use argument wake_mask_hi to return mask */
+ wake_msk->wake_mask_hi |= (1ULL << index);
+ } else {
+ trigger_val = (flow_type & IRQF_TRIGGER_MASK);
+ if ((tegra_wake_event_data[index].polarity ==
+ POLARITY_EDGE_ANY) ||
+ (trigger_val ==
+ (IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING))) {
+ pr_debug("Wake%d flow_type=ANY\n", index);
+ wake_msk->wake_mask_any |= (1ULL << index);
+ } else if ((trigger_val == IRQF_TRIGGER_HIGH) ||
+ (trigger_val == IRQF_TRIGGER_RISING)) {
+ pr_debug("Wake%d flow_type=HI\n", index);
+ wake_msk->wake_mask_hi |= (1ULL << index);
+ } else if ((trigger_val == IRQF_TRIGGER_LOW) ||
+ (trigger_val == IRQF_TRIGGER_FALLING)) {
+ pr_debug("Wake%d flow_type=LO\n", index);
+ wake_msk->wake_mask_lo |= (1ULL << index);
+ } else {
+ pr_err("Error: Wake%d UNKNOWN flow_type=%d\n",
+ index, flow_type);
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+int tegra_irq_to_wake(unsigned int irq, int flow_type,
+ struct wake_mask_types *wake_msk)
+{
+ int i;
+ int err;
+
+ wake_msk->wake_mask_hi = 0ULL;
+ wake_msk->wake_mask_lo = 0ULL;
+ wake_msk->wake_mask_any = 0ULL;
+ /*
+ * check for irq based on tegra_wake_event_data table
+ */
+ for (i = 0; i < tegra_wake_event_data_size; i++) {
+ if (tegra_wake_event_data[i].irq == irq) {
+ err = update_wake_mask(i, flow_type, wake_msk);
+ if (err)
+ return err;
+ continue;
+ }
+ }
+
+ if (wake_msk->wake_mask_hi || wake_msk->wake_mask_lo ||
+ wake_msk->wake_mask_any) {
+ pr_debug("Enabling wake sources for irq=%d, mask hi=%#llx, lo=%#llx, any=%#llx, flow_type=%d\n",
+ irq, wake_msk->wake_mask_hi, wake_msk->wake_mask_lo,
+ wake_msk->wake_mask_any, flow_type);
+ return 0;
+ }
+ return -EINVAL;
+}
+
+int tegra_wake_to_irq(int wake)
+{
+ if (wake < 0)
+ return -EINVAL;
+
+ if (wake >= tegra_wake_event_data_size)
+ return -EINVAL;
+
+ return tegra_wake_event_data[wake].irq;
+}
+
+int tegra_disable_wake_source(int wake)
+{
+ if (wake >= tegra_wake_event_data_size)
+ return -EINVAL;
+
+ tegra_wake_event_data[wake].irq = -EINVAL;
+
+ return 0;
+}
+
diff --git a/arch/arm/mach-tegra/wakeups.h b/arch/arm/mach-tegra/wakeups.h
new file mode 100644
index 000000000000..6d2f5f077601
--- /dev/null
+++ b/arch/arm/mach-tegra/wakeups.h
@@ -0,0 +1,48 @@
+/*
+ * 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/>.
+ */
+
+#ifndef __WAKEUPS_H_
+#define __WAKEUPS_H_
+
+struct wake_mask_types {
+ u64 wake_mask_hi;
+ u64 wake_mask_lo;
+ u64 wake_mask_any;
+};
+
+/* sets 64-bit wake mask argument bits for wake sources given an irq */
+int tegra_irq_to_wake(unsigned int irq, int flow_type,
+ struct wake_mask_types *wake_msk);
+/*
+ * given wake source index, returns irq number or negative value for error
+ */
+int tegra_wake_to_irq(int wake);
+/* disable selected wake source setting for particular board */
+int tegra_disable_wake_source(int wake);
+
+enum wake_polarity {
+ POLARITY_NONE = 0,
+ POLARITY_LEVEL_HI,
+ POLARITY_LEVEL_LO,
+ POLARITY_EDGE_ANY
+};
+
+struct tegra_wake_info {
+ int irq;
+ enum wake_polarity polarity;
+};
+
+#endif /* end __WAKEUPS_H_ */
diff --git a/arch/arm/mach-tegra/wdt-recovery.c b/arch/arm/mach-tegra/wdt-recovery.c
index 537b1c0db853..c0a1a1fea347 100644
--- a/arch/arm/mach-tegra/wdt-recovery.c
+++ b/arch/arm/mach-tegra/wdt-recovery.c
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/wdt-recovery.c
*
- * Copyright (c) 2011, NVIDIA Corporation.
+ * 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
@@ -30,7 +30,7 @@
#include <asm/mach/time.h>
#include <asm/localtimer.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include <mach/irqs.h>
#include <mach/iomap.h>
#include <mach/clk.h>
@@ -45,7 +45,7 @@ static int wdt_heartbeat = 30;
#define TIMER_PCR 0x4
#define TIMER_PCR_INTR (1 << 30)
#define WDT_CFG (0)
- #define WDT_CFG_TMR_SRC (7 << 0) /* for TMR7. */
+ #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_SYS_RST_EN (1 << 14)
@@ -56,8 +56,8 @@ static int wdt_heartbeat = 30;
#define WDT_UNLOCK (0xC)
#define WDT_UNLOCK_PATTERN (0xC45A << 0)
-static void __iomem *wdt_timer = IO_ADDRESS(TEGRA_TMR7_BASE);
-static void __iomem *wdt_source = IO_ADDRESS(TEGRA_WDT0_BASE);
+static void __iomem *wdt_timer = IO_ADDRESS(TEGRA_TMR10_BASE);
+static void __iomem *wdt_source = IO_ADDRESS(TEGRA_WDT3_BASE);
static void tegra_wdt_reset_enable(void)
{
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index aaea6d487bae..e23ad5ebc330 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -885,6 +885,17 @@ config ARM_DMA_MEM_BUFFERABLE
You are recommended say 'Y' here and debug any affected drivers.
+config NON_ALIASED_COHERENT_MEM
+ bool "Avoid aliasing mappings in DMA coherent allocator" if CPU_V7
+ help
+ Avoid multiple mappings with DMA coherent/writecombine allocator by
+ pre-allocating the mappings, and removing that memory from the
+ system memory mapping.
+
+ This will make sure DMA memory is fully coherent, so cache
+ dma_sync APIs will not be necessary to maintain cache cohereny
+ for DMA coherent region.
+
config ARCH_HAS_BARRIERS
bool
help
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
index 47e2e3ba1902..c3ef2961ddff 100644
--- a/arch/arm/mm/Makefile
+++ b/arch/arm/mm/Makefile
@@ -2,9 +2,15 @@
# Makefile for the linux arm-specific parts of the memory manager.
#
-obj-y := dma-mapping.o extable.o fault.o init.o \
+obj-y := extable.o fault.o init.o \
iomap.o
+ifeq ($(CONFIG_NON_ALIASED_COHERENT_MEM),y)
+obj-y += dma-na-mapping.o
+else
+obj-y += dma-mapping.o
+endif
+
obj-$(CONFIG_MMU) += fault-armv.o flush.o idmap.o ioremap.o \
mmap.o pgd.o mmu.o vmregion.o pageattr.o
diff --git a/arch/arm/mm/dma-na-mapping.c b/arch/arm/mm/dma-na-mapping.c
new file mode 100644
index 000000000000..4e5d52dda285
--- /dev/null
+++ b/arch/arm/mm/dma-na-mapping.c
@@ -0,0 +1,748 @@
+/*
+ * linux/arch/arm/mm/dma-mapping.c
+ *
+ * Copyright (C) 2000-2004 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * DMA uncached mapping support.
+ */
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/gfp.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/highmem.h>
+#include <linux/memblock.h>
+
+#include <asm/memory.h>
+#include <asm/highmem.h>
+#include <asm/cacheflush.h>
+#include <asm/tlbflush.h>
+#include <asm/sizes.h>
+#include <asm/mach/map.h>
+
+#include "mm.h"
+
+static u64 get_coherent_dma_mask(struct device *dev)
+{
+ u64 mask = (u64)arm_dma_limit;
+
+ if (dev) {
+ mask = dev->coherent_dma_mask;
+
+ /*
+ * Sanity check the DMA mask - it must be non-zero, and
+ * must be able to be satisfied by a DMA allocation.
+ */
+ if (mask == 0) {
+ dev_warn(dev, "coherent DMA mask is unset\n");
+ return 0;
+ }
+
+ if ((~mask) & (u64)arm_dma_limit) {
+ dev_warn(dev, "coherent DMA mask %#llx is smaller "
+ "than system GFP_DMA mask %#llx\n",
+ mask, (u64)arm_dma_limit);
+ return 0;
+ }
+ }
+
+ return mask;
+}
+
+/*
+ * Allocate a DMA buffer for 'dev' of size 'size' using the
+ * specified gfp mask. Note that 'size' must be page aligned.
+ */
+static struct page *__dma_alloc_buffer(struct device *dev,
+ size_t size, gfp_t gfp)
+{
+ unsigned long order = get_order(size);
+ struct page *page, *p, *e;
+ void *ptr;
+ u64 mask = get_coherent_dma_mask(dev);
+
+#ifdef CONFIG_DMA_API_DEBUG
+ u64 limit = (mask + 1) & ~mask;
+ if (limit && size >= limit) {
+ dev_warn(dev, "coherent allocation too big"
+ "(requested %#x mask %#llx)\n",
+ size, mask);
+ return NULL;
+ }
+#endif
+
+ if (!mask)
+ return NULL;
+
+ if (mask < 0xffffffffULL)
+ gfp |= GFP_DMA;
+
+ page = alloc_pages(gfp, order);
+ if (!page)
+ return NULL;
+
+ /*
+ * Now split the huge page and free the excess pages
+ */
+ split_page(page, order);
+ for (p = page + (size >> PAGE_SHIFT), e = page + (1 << order);
+ p < e; p++)
+ __free_page(p);
+
+ /*
+ * Ensure that the allocated pages are zeroed, and that any data
+ * lurking in the kernel direct-mapped region is invalidated.
+ */
+ ptr = page_address(page);
+ memset(ptr, 0, size);
+ dmac_flush_range(ptr, ptr + size);
+ outer_flush_range(__pa(ptr), __pa(ptr) + size);
+
+ return page;
+}
+
+/*
+ * Free a DMA buffer. 'size' must be page aligned.
+ */
+static void __dma_free_buffer(struct page *page, size_t size)
+{
+ struct page *e = page + (size >> PAGE_SHIFT);
+
+ while (page < e) {
+ __free_page(page);
+ page++;
+ }
+}
+
+#ifdef CONFIG_MMU
+/* Sanity check sizes */
+#if CONSISTENT_DMA_SIZE % SECTION_SIZE
+#error "CONSISTENT_DMA_SIZE must be a multiple of the section size"
+#endif
+#if CONSISTENT_WC_SIZE % SECTION_SIZE
+#error "CONSISTENT_WC_SIZE must be a multiple of the section size"
+#endif
+#if ((CONSISTENT_DMA_SIZE + CONSISTENT_WC_SIZE) % SZ_2M)
+#error "Sum of CONSISTENT_DMA_SIZE and CONSISTENT_WC_SIZE must " \
+ "be multiple of 2MiB"
+#endif
+
+#include "vmregion.h"
+
+struct dma_coherent_area {
+ struct arm_vmregion_head vm;
+ unsigned long pfn;
+ unsigned long pfn_end;
+ unsigned int type;
+ const char *name;
+};
+
+static struct dma_coherent_area coherent_wc_head = {
+ .vm = {
+ .vm_start = CONSISTENT_WC_BASE,
+ .vm_end = CONSISTENT_WC_END,
+ },
+ .pfn = 0,
+ .pfn_end = 0,
+ .type = MT_WC_COHERENT,
+ .name = "WC ",
+};
+
+static struct dma_coherent_area coherent_dma_head = {
+ .vm = {
+ .vm_start = CONSISTENT_BASE,
+ .vm_end = CONSISTENT_END,
+ },
+ .pfn = 0,
+ .pfn_end = 0,
+ .type = MT_DMA_COHERENT,
+ .name = "DMA coherent ",
+};
+
+static struct dma_coherent_area *coherent_areas[2] __initdata = {
+ &coherent_wc_head,
+ &coherent_dma_head
+};
+
+static struct dma_coherent_area *coherent_map[2];
+#define coherent_wc_area coherent_map[0]
+#define coherent_dma_area coherent_map[1]
+
+void dma_coherent_reserve(void)
+{
+ phys_addr_t base;
+ unsigned long size;
+ int can_share, i;
+
+ if (arch_is_coherent())
+ return;
+
+#ifdef CONFIG_ARM_DMA_MEM_BUFFERABLE
+ /* ARMv6: only when DMA_MEM_BUFFERABLE is enabled */
+ can_share = cpu_architecture() >= CPU_ARCH_ARMv6;
+#else
+ /* ARMv7+: WC and DMA areas have the same properties, so can share */
+ can_share = cpu_architecture() >= CPU_ARCH_ARMv7;
+#endif
+ if (can_share) {
+ coherent_wc_head.name = "DMA coherent/WC ";
+ coherent_wc_head.vm.vm_end = coherent_dma_head.vm.vm_end;
+ coherent_dma_head.vm.vm_start = coherent_dma_head.vm.vm_end;
+ coherent_dma_area = coherent_wc_area = &coherent_wc_head;
+ } else {
+ memcpy(coherent_map, coherent_areas, sizeof(coherent_map));
+ }
+
+ for (i = 0; i < ARRAY_SIZE(coherent_areas); i++) {
+ struct dma_coherent_area *area = coherent_areas[i];
+
+ size = area->vm.vm_end - area->vm.vm_start;
+ if (!size)
+ continue;
+
+ spin_lock_init(&area->vm.vm_lock);
+ INIT_LIST_HEAD(&area->vm.vm_list);
+
+ base = memblock_end_of_DRAM() - size;
+ memblock_free(base, size);
+ memblock_remove(base, size);
+
+ area->pfn = __phys_to_pfn(base);
+ area->pfn_end = __phys_to_pfn(base+size);
+
+ pr_info("DMA: %luMiB %smemory allocated at 0x%08llx phys\n",
+ size / 1048576, area->name, (unsigned long long)base);
+ }
+}
+
+void __init dma_coherent_mapping(void)
+{
+ struct map_desc map[ARRAY_SIZE(coherent_areas)];
+ int nr;
+
+ for (nr = 0; nr < ARRAY_SIZE(map); nr++) {
+ struct dma_coherent_area *area = coherent_areas[nr];
+
+ map[nr].pfn = area->pfn;
+ map[nr].virtual = area->vm.vm_start;
+ map[nr].length = area->vm.vm_end - area->vm.vm_start;
+ map[nr].type = area->type;
+ if (map[nr].length == 0)
+ break;
+ }
+
+ iotable_init(map, nr);
+}
+
+static void *dma_alloc_area(size_t size, unsigned long *pfn, gfp_t gfp,
+ struct dma_coherent_area *area)
+{
+ struct arm_vmregion *c;
+ size_t align;
+ int bit;
+
+ /*
+ * Align the virtual region allocation - maximum alignment is
+ * a section size, minimum is a page size. This helps reduce
+ * fragmentation of the DMA space, and also prevents allocations
+ * smaller than a section from crossing a section boundary.
+ */
+ bit = fls(size - 1);
+ if (bit > SECTION_SHIFT)
+ bit = SECTION_SHIFT;
+ align = 1 << bit;
+
+ /*
+ * Allocate a virtual address in the consistent mapping region.
+ */
+ c = arm_vmregion_alloc(&area->vm, align, size,
+ gfp & ~(__GFP_DMA | __GFP_HIGHMEM));
+ if (!c)
+ return NULL;
+
+ memset((void *)c->vm_start, 0, size);
+ *pfn = area->pfn + ((c->vm_start - area->vm.vm_start) >> PAGE_SHIFT);
+ c->vm_pages = pfn_to_page(*pfn);
+
+ return (void *)c->vm_start;
+}
+
+static void dma_free_area(void *cpu_addr, size_t size,
+ struct dma_coherent_area *area)
+{
+ struct arm_vmregion *c;
+
+ c = arm_vmregion_find_remove(&area->vm, (unsigned long)cpu_addr);
+ if (!c) {
+ printk(KERN_ERR "%s: trying to free invalid coherent area: %p\n",
+ __func__, cpu_addr);
+ dump_stack();
+ return;
+ }
+
+ if ((c->vm_end - c->vm_start) != size) {
+ printk(KERN_ERR "%s: freeing wrong coherent size (%ld != %d)\n",
+ __func__, c->vm_end - c->vm_start, size);
+ dump_stack();
+ size = c->vm_end - c->vm_start;
+ }
+
+ arm_vmregion_free(&area->vm, c);
+}
+
+#define nommu() (0)
+
+#else /* !CONFIG_MMU */
+
+#define dma_alloc_area(size, pfn, gfp, area) ({ *(pfn) = 0; NULL })
+#define dma_free_area(addr, size, area) do { } while (0)
+
+#define nommu() (1)
+#define coherent_wc_area NULL
+#define coherent_dma_area NULL
+
+void dma_coherent_reserve(void)
+{
+}
+
+#endif /* CONFIG_MMU */
+
+static void *
+__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
+ struct dma_coherent_area *area)
+{
+
+ unsigned long pfn;
+ void *ret;
+ /* Following is a work-around (a.k.a. hack) to prevent pages
+ * with __GFP_COMP being passed to split_page() which cannot
+ * handle them. The real problem is that this flag probably
+ * should be 0 on ARM as it is not supported on this
+ * platform--see CONFIG_HUGETLB_PAGE. */
+ gfp &= ~(__GFP_COMP);
+
+ *handle = ~0;
+ size = PAGE_ALIGN(size);
+
+ if (arch_is_coherent() || nommu()) {
+ struct page *page = __dma_alloc_buffer(dev, size, gfp);
+ if (!page)
+ return NULL;
+ pfn = page_to_pfn(page);
+ ret = page_address(page);
+ } else {
+ ret = dma_alloc_area(size, &pfn, gfp, area);
+ }
+
+ if (ret)
+ *handle = pfn_to_dma(dev, pfn);
+
+ return ret;
+}
+
+static void __dma_free(struct device *dev, size_t size, void *cpu_addr,
+ dma_addr_t handle, struct dma_coherent_area *area)
+{
+ size = PAGE_ALIGN(size);
+
+ if (arch_is_coherent() || nommu())
+ __dma_free_buffer(pfn_to_page(dma_to_pfn(dev, handle)), size);
+ else
+ dma_free_area(cpu_addr, size, area);
+}
+
+/*
+ * Allocate DMA-coherent memory space and return both the kernel remapped
+ * virtual and bus address for that space.
+ */
+void *
+dma_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *handle, gfp_t gfp)
+{
+ void *memory;
+
+ if (dma_alloc_from_coherent(dev, size, handle, &memory))
+ return memory;
+
+ return __dma_alloc(dev, size, handle, gfp, coherent_dma_area);
+}
+EXPORT_SYMBOL(dma_alloc_coherent);
+
+/*
+ * Allocate a writecombining region, in much the same way as
+ * dma_alloc_coherent above.
+ */
+void *
+dma_alloc_writecombine(struct device *dev, size_t size,
+ dma_addr_t *handle, gfp_t gfp)
+{
+ return __dma_alloc(dev, size, handle, gfp, coherent_wc_area);
+}
+EXPORT_SYMBOL(dma_alloc_writecombine);
+
+static int dma_mmap(struct device *dev, struct vm_area_struct *vma,
+ void *cpu_addr, dma_addr_t dma_addr, size_t size,
+ struct dma_coherent_area *area)
+{
+ int ret = -ENXIO;
+#ifdef CONFIG_MMU
+ unsigned long user_size, kern_size;
+ struct arm_vmregion *c;
+
+ user_size = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+
+ c = arm_vmregion_find(&area->vm, (unsigned long)cpu_addr);
+ if (c) {
+ unsigned long off = vma->vm_pgoff;
+
+ kern_size = (c->vm_end - c->vm_start) >> PAGE_SHIFT;
+
+ if (off < kern_size &&
+ user_size <= (kern_size - off)) {
+ ret = remap_pfn_range(vma, vma->vm_start,
+ page_to_pfn(c->vm_pages) + off,
+ user_size << PAGE_SHIFT,
+ vma->vm_page_prot);
+ }
+ }
+#endif /* CONFIG_MMU */
+
+ return ret;
+}
+
+int dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
+ void *cpu_addr, dma_addr_t dma_addr, size_t size)
+{
+ vma->vm_page_prot = pgprot_dmacoherent(vma->vm_page_prot);
+ return dma_mmap(dev, vma, cpu_addr, dma_addr, size, coherent_dma_area);
+}
+EXPORT_SYMBOL(dma_mmap_coherent);
+
+int dma_mmap_writecombine(struct device *dev, struct vm_area_struct *vma,
+ void *cpu_addr, dma_addr_t dma_addr, size_t size)
+{
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+ return dma_mmap(dev, vma, cpu_addr, dma_addr, size, coherent_wc_area);
+}
+EXPORT_SYMBOL(dma_mmap_writecombine);
+
+/*
+ * free a page as defined by the above mapping.
+ * Must not be called with IRQs disabled.
+ */
+void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
+ dma_addr_t handle)
+{
+ WARN_ON(irqs_disabled());
+
+ if (dma_release_from_coherent(dev, get_order(size), cpu_addr))
+ return;
+
+ __dma_free(dev, size, cpu_addr, handle, coherent_dma_area);
+}
+EXPORT_SYMBOL(dma_free_coherent);
+
+void dma_free_writecombine(struct device *dev, size_t size, void *cpu_addr,
+ dma_addr_t handle)
+{
+ WARN_ON(irqs_disabled());
+
+ __dma_free(dev, size, cpu_addr, handle, coherent_wc_area);
+}
+EXPORT_SYMBOL(dma_free_writecombine);
+
+#define is_coherent_pfn(x) ((((x) >= coherent_wc_head.pfn) && \
+ ((x) < coherent_wc_head.pfn_end)) || \
+ (((x) >= coherent_dma_head.pfn) && \
+ ((x) < coherent_dma_head.pfn_end)))
+/*
+ * Make an area consistent for devices.
+ * Note: Drivers should NOT use this function directly, as it will break
+ * platforms with CONFIG_DMABOUNCE.
+ * Use the driver DMA support - see dma-mapping.h (dma_sync_*)
+ */
+void ___dma_single_cpu_to_dev(struct device *dev, const void *kaddr,
+ size_t size, enum dma_data_direction dir)
+{
+ unsigned long paddr;
+ unsigned long kaddr_pfn;
+
+ kaddr_pfn = dma_to_pfn(dev, virt_to_dma(dev, (void *)kaddr));
+
+ if (is_coherent_pfn(kaddr_pfn))
+ return;
+
+ BUG_ON(!virt_addr_valid(kaddr) || !virt_addr_valid(kaddr + size - 1));
+
+ dmac_map_area(kaddr, size, dir);
+
+ paddr = __pa(kaddr);
+ if (dir == DMA_FROM_DEVICE)
+ outer_inv_range(paddr, paddr + size);
+ else
+ outer_clean_range(paddr, paddr + size);
+
+ /* FIXME: non-speculating: flush on bidirectional mappings? */
+}
+EXPORT_SYMBOL(___dma_single_cpu_to_dev);
+
+void ___dma_single_dev_to_cpu(struct device *dev, const void *kaddr,
+ size_t size, enum dma_data_direction dir)
+{
+ unsigned long kaddr_pfn;
+
+ kaddr_pfn = dma_to_pfn(dev, virt_to_dma(dev, (void *)kaddr));
+
+ if (is_coherent_pfn(kaddr_pfn))
+ return;
+
+ BUG_ON(!virt_addr_valid(kaddr) || !virt_addr_valid(kaddr + size - 1));
+
+ /* FIXME: non-speculating: not required */
+ /* don't bother invalidating if DMA to device */
+ if (dir != DMA_TO_DEVICE) {
+ unsigned long paddr = __pa(kaddr);
+ outer_inv_range(paddr, paddr + size);
+ }
+
+ dmac_unmap_area(kaddr, size, dir);
+}
+EXPORT_SYMBOL(___dma_single_dev_to_cpu);
+
+static void dma_cache_maint_page(struct page *page, unsigned long offset,
+ size_t size, enum dma_data_direction dir,
+ void (*op)(const void *, size_t, int))
+{
+ /*
+ * A single sg entry may refer to multiple physically contiguous
+ * pages. But we still need to process highmem pages individually.
+ * If highmem is not configured then the bulk of this loop gets
+ * optimized out.
+ */
+ size_t left = size;
+ do {
+ size_t len = left;
+ void *vaddr;
+
+ if (PageHighMem(page)) {
+ if (len + offset > PAGE_SIZE) {
+ if (offset >= PAGE_SIZE) {
+ page += offset / PAGE_SIZE;
+ offset %= PAGE_SIZE;
+ }
+ len = PAGE_SIZE - offset;
+ }
+ vaddr = kmap_high_get(page);
+ if (vaddr) {
+ vaddr += offset;
+ op(vaddr, len, dir);
+ kunmap_high(page);
+ } else if (cache_is_vipt()) {
+ /* unmapped pages might still be cached */
+ vaddr = kmap_atomic(page);
+ op(vaddr + offset, len, dir);
+ kunmap_atomic(vaddr);
+ }
+ } else {
+ vaddr = page_address(page) + offset;
+ op(vaddr, len, dir);
+ }
+ offset = 0;
+ page++;
+ left -= len;
+ } while (left);
+}
+
+void ___dma_page_cpu_to_dev(struct page *page, unsigned long off,
+ size_t size, enum dma_data_direction dir)
+{
+ unsigned long paddr;
+
+ dma_cache_maint_page(page, off, size, dir, dmac_map_area);
+
+ paddr = page_to_phys(page) + off;
+ if (dir == DMA_FROM_DEVICE)
+ outer_inv_range(paddr, paddr + size);
+ else
+ outer_clean_range(paddr, paddr + size);
+ /* FIXME: non-speculating: flush on bidirectional mappings? */
+}
+EXPORT_SYMBOL(___dma_page_cpu_to_dev);
+
+void ___dma_page_dev_to_cpu(struct page *page, unsigned long off,
+ size_t size, enum dma_data_direction dir)
+{
+ unsigned long paddr = page_to_phys(page) + off;
+
+ /* FIXME: non-speculating: not required */
+ /* don't bother invalidating if DMA to device */
+ if (dir != DMA_TO_DEVICE)
+ outer_inv_range(paddr, paddr + size);
+
+ dma_cache_maint_page(page, off, size, dir, dmac_unmap_area);
+
+ /*
+ * Mark the D-cache clean for this page to avoid extra flushing.
+ */
+ if (dir != DMA_TO_DEVICE && off == 0 && size >= PAGE_SIZE)
+ set_bit(PG_dcache_clean, &page->flags);
+}
+EXPORT_SYMBOL(___dma_page_dev_to_cpu);
+
+/**
+ * dma_map_sg - map a set of SG buffers for streaming mode DMA
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @sg: list of buffers
+ * @nents: number of buffers to map
+ * @dir: DMA transfer direction
+ *
+ * Map a set of buffers described by scatterlist in streaming mode for DMA.
+ * This is the scatter-gather version of the dma_map_single interface.
+ * Here the scatter gather list elements are each tagged with the
+ * appropriate dma address and length. They are obtained via
+ * sg_dma_{address,length}.
+ *
+ * Device ownership issues as mentioned for dma_map_single are the same
+ * here.
+ */
+int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+ enum dma_data_direction dir)
+{
+ struct scatterlist *s;
+ int i, j;
+
+ BUG_ON(!valid_dma_direction(dir));
+
+ for_each_sg(sg, s, nents, i) {
+ s->dma_address = __dma_map_page(dev, sg_page(s), s->offset,
+ s->length, dir);
+ if (dma_mapping_error(dev, s->dma_address))
+ goto bad_mapping;
+ }
+ debug_dma_map_sg(dev, sg, nents, nents, dir);
+ return nents;
+
+ bad_mapping:
+ for_each_sg(sg, s, i, j)
+ __dma_unmap_page(dev, sg_dma_address(s), sg_dma_len(s), dir);
+ return 0;
+}
+EXPORT_SYMBOL(dma_map_sg);
+
+/**
+ * dma_unmap_sg - unmap a set of SG buffers mapped by dma_map_sg
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @sg: list of buffers
+ * @nents: number of buffers to unmap (same as was passed to dma_map_sg)
+ * @dir: DMA transfer direction (same as was passed to dma_map_sg)
+ *
+ * Unmap a set of streaming mode DMA translations. Again, CPU access
+ * rules concerning calls here are the same as for dma_unmap_single().
+ */
+void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
+ enum dma_data_direction dir)
+{
+ struct scatterlist *s;
+ int i;
+
+ debug_dma_unmap_sg(dev, sg, nents, dir);
+
+ for_each_sg(sg, s, nents, i)
+ __dma_unmap_page(dev, sg_dma_address(s), sg_dma_len(s), dir);
+}
+EXPORT_SYMBOL(dma_unmap_sg);
+
+/**
+ * dma_sync_sg_for_cpu
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @sg: list of buffers
+ * @nents: number of buffers to map (returned from dma_map_sg)
+ * @dir: DMA transfer direction (same as was passed to dma_map_sg)
+ */
+void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir)
+{
+ struct scatterlist *s;
+ int i;
+
+ for_each_sg(sg, s, nents, i) {
+ if (!dmabounce_sync_for_cpu(dev, sg_dma_address(s), 0,
+ sg_dma_len(s), dir))
+ continue;
+
+ __dma_page_dev_to_cpu(sg_page(s), s->offset,
+ s->length, dir);
+ }
+
+ debug_dma_sync_sg_for_cpu(dev, sg, nents, dir);
+}
+EXPORT_SYMBOL(dma_sync_sg_for_cpu);
+
+/**
+ * dma_sync_sg_for_device
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @sg: list of buffers
+ * @nents: number of buffers to map (returned from dma_map_sg)
+ * @dir: DMA transfer direction (same as was passed to dma_map_sg)
+ */
+void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir)
+{
+ struct scatterlist *s;
+ int i;
+
+ for_each_sg(sg, s, nents, i) {
+ if (!dmabounce_sync_for_device(dev, sg_dma_address(s), 0,
+ sg_dma_len(s), dir))
+ continue;
+
+ __dma_page_cpu_to_dev(sg_page(s), s->offset,
+ s->length, dir);
+ }
+
+ debug_dma_sync_sg_for_device(dev, sg, nents, dir);
+}
+EXPORT_SYMBOL(dma_sync_sg_for_device);
+
+/*
+ * Return whether the given device DMA address mask can be supported
+ * properly. For example, if your device can only drive the low 24-bits
+ * during bus mastering, then you would pass 0x00ffffff as the mask
+ * to this function.
+ */
+int dma_supported(struct device *dev, u64 mask)
+{
+ if (mask < (u64)arm_dma_limit)
+ return 0;
+ return 1;
+}
+EXPORT_SYMBOL(dma_supported);
+
+int dma_set_mask(struct device *dev, u64 dma_mask)
+{
+ if (!dev->dma_mask || !dma_supported(dev, dma_mask))
+ return -EIO;
+
+#ifndef CONFIG_DMABOUNCE
+ *dev->dma_mask = dma_mask;
+#endif
+
+ return 0;
+}
+EXPORT_SYMBOL(dma_set_mask);
+
+#define PREALLOC_DMA_DEBUG_ENTRIES 4096
+
+static int __init dma_debug_do_init(void)
+{
+ dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES);
+ return 0;
+}
+fs_initcall(dma_debug_do_init);
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index f8037ba338ac..6f81c8e05c3a 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -364,6 +364,9 @@ void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc)
#endif
arm_mm_memblock_reserve();
+#if defined(CONFIG_NON_ALIASED_COHERENT_MEM)
+ dma_coherent_reserve();
+#endif
arm_dt_memblock_reserve();
/* reserve any platform specific memblock areas */
diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h
index 010566799c80..967a8048f321 100644
--- a/arch/arm/mm/mm.h
+++ b/arch/arm/mm/mm.h
@@ -31,3 +31,8 @@ extern u32 arm_dma_limit;
void __init bootmem_init(void);
void arm_mm_memblock_reserve(void);
+
+#ifdef CONFIG_NON_ALIASED_COHERENT_MEM
+void dma_coherent_reserve(void);
+void dma_coherent_mapping(void);
+#endif
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 4fa9c246ae93..bb80555edac9 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -273,6 +273,18 @@ static struct mem_type mem_types[] = {
.prot_l1 = PMD_TYPE_TABLE,
.domain = DOMAIN_KERNEL,
},
+#ifdef CONFIG_NON_ALIASED_COHERENT_MEM
+ [MT_DMA_COHERENT] = {
+ .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE |
+ PMD_SECT_S,
+ .domain = DOMAIN_IO,
+ },
+ [MT_WC_COHERENT] = {
+ .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE |
+ PMD_SECT_S,
+ .domain = DOMAIN_IO,
+ },
+#endif
};
const struct mem_type *get_mem_type(unsigned int type)
@@ -353,6 +365,9 @@ static void __init build_mem_type_table(void)
mem_types[MT_DEVICE_NONSHARED].prot_sect |= PMD_SECT_XN;
mem_types[MT_DEVICE_CACHED].prot_sect |= PMD_SECT_XN;
mem_types[MT_DEVICE_WC].prot_sect |= PMD_SECT_XN;
+#ifdef CONFIG_NON_ALIASED_COHERENT_MEM
+ mem_types[MT_DMA_COHERENT].prot_sect |= PMD_SECT_XN;
+#endif
}
if (cpu_arch >= CPU_ARCH_ARMv7 && (cr & CR_TRE)) {
/*
@@ -457,13 +472,30 @@ static void __init build_mem_type_table(void)
/* Non-cacheable Normal is XCB = 001 */
mem_types[MT_MEMORY_NONCACHED].prot_sect |=
PMD_SECT_BUFFERED;
+#ifdef CONFIG_NON_ALIASED_COHERENT_MEM
+ mem_types[MT_WC_COHERENT].prot_sect |=
+ PMD_SECT_BUFFERED;
+ mem_types[MT_DMA_COHERENT].prot_sect |=
+ PMD_SECT_BUFFERED;
+#endif
} else {
/* For both ARMv6 and non-TEX-remapping ARMv7 */
mem_types[MT_MEMORY_NONCACHED].prot_sect |=
PMD_SECT_TEX(1);
+#ifdef CONFIG_NON_ALIASED_COHERENT_MEM
+ mem_types[MT_WC_COHERENT].prot_sect |=
+ PMD_SECT_TEX(1);
+#ifdef CONFIG_ARM_DMA_MEM_BUFFERABLE
+ mem_types[MT_DMA_COHERENT].prot_sect |=
+ PMD_SECT_TEX(1);
+#endif
+#endif
}
} else {
mem_types[MT_MEMORY_NONCACHED].prot_sect |= PMD_SECT_BUFFERABLE;
+#ifdef CONFIG_NON_ALIASED_COHERENT_MEM
+ mem_types[MT_WC_COHERENT].prot_sect |= PMD_SECT_BUFFERED;
+#endif
}
for (i = 0; i < 16; i++) {
@@ -986,6 +1018,10 @@ static void __init devicemaps_init(struct machine_desc *mdesc)
create_mapping(&map);
}
+#ifdef CONFIG_NON_ALIASED_COHERENT_MEM
+ dma_coherent_mapping();
+#endif
+
/*
* Ask the machine support to map in the statically mapped devices.
*/
diff --git a/arch/arm/mm/pageattr.c b/arch/arm/mm/pageattr.c
index 5f8071110e88..b7ff7f19b541 100644
--- a/arch/arm/mm/pageattr.c
+++ b/arch/arm/mm/pageattr.c
@@ -331,6 +331,10 @@ static void __set_pmd_pte(pmd_t *pmd, unsigned long address, pte_t *pte)
cpa_debug("__set_pmd_pte %x %x %x\n", pmd, pte, *pte);
+ /* enforce pte entry stores ordering to avoid pmd writes
+ * bypassing pte stores.
+ */
+ dsb();
/* change init_mm */
pmd_populate_kernel(&init_mm, pmd, pte);
@@ -342,7 +346,10 @@ static void __set_pmd_pte(pmd_t *pmd, unsigned long address, pte_t *pte)
pgd_index(address), address);
pmd_populate_kernel(NULL, pmd, pte);
}
-
+ /* enforce pmd entry stores ordering to avoid tlb flush bypassing
+ * pmd entry stores.
+ */
+ dsb();
}
static int
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index 38c78253f769..a502958a71f8 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -551,6 +551,12 @@ __v7_setup:
mrcge p15, 0, r10, c15, c0, 0 @ read power control register
orrge r10, r10, #1 @ enable dynamic clock gating
mcrge p15, 0, r10, c15, c0, 0 @ write power control register
+#ifdef CONFIG_ARM_ERRATA_716044
+ cmp r6, #0x12 @ present in r1p0 - r1p2
+ mrcle p15, 0, r10, c1, c0, 0
+ orrle r10, r10, #(1 << 14) @ set SCTLR.RR
+ mcrle p15, 0, r10, c1, c0, 0
+#endif
#ifdef CONFIG_ARM_ERRATA_720791
teq r5, #0x00100000 @ only present in r1p*
mrceq p15, 0, r10, c15, c0, 2 @ read "chicken power ctrl" reg
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index 6a46b56f7538..462a94d2a2c1 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/cpu.h>
+#include <linux/hardirq.h>
#include <linux/kernel.h>
#include <linux/notifier.h>
#include <linux/signal.h>
@@ -425,7 +426,10 @@ void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)
static void vfp_enable(void *unused)
{
- u32 access = get_copro_access();
+ u32 access;
+
+ BUG_ON(preemptible());
+ access = get_copro_access();
/*
* Enable full access to VFP (cp10 and cp11)
@@ -574,11 +578,8 @@ static int __init vfp_init(void)
unsigned int vfpsid;
unsigned int cpu_arch = cpu_architecture();
-#ifdef CONFIG_SMP
- preempt_disable();
-#endif
if (cpu_arch >= CPU_ARCH_ARMv6)
- vfp_enable(NULL);
+ on_each_cpu(vfp_enable, NULL, 1);
/*
* First check that there is a VFP that we can use.
@@ -599,8 +600,6 @@ static int __init vfp_init(void)
} else {
hotcpu_notifier(vfp_hotplug, 0);
- smp_call_function(vfp_enable, NULL, 1);
-
VFP_arch = (vfpsid & FPSID_ARCH_MASK) >> FPSID_ARCH_BIT; /* Extract the architecture version */
printk("implementor %02x architecture %d part %02x variant %x rev %x\n",
(vfpsid & FPSID_IMPLEMENTER_MASK) >> FPSID_IMPLEMENTER_BIT,
@@ -647,9 +646,6 @@ static int __init vfp_init(void)
elf_hwcap |= HWCAP_VFPv4;
}
}
-#ifdef CONFIG_SMP
- preempt_enable();
-#endif
return 0;
}
diff --git a/chromeos/config/armel/config.common.armel b/chromeos/config/armel/config.common.armel
new file mode 100644
index 000000000000..98451e005db9
--- /dev/null
+++ b/chromeos/config/armel/config.common.armel
@@ -0,0 +1,537 @@
+#
+# Config options generated by splitconfig
+#
+CONFIG_AEABI=y
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_APM_EMULATION is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_BCMRING is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CNS3XXX is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_DOVE is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_EXYNOS4 is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_H720X is not set
+CONFIG_ARCH_HAS_CPUFREQ=y
+CONFIG_ARCH_HAS_SUSPEND_PAGETABLE=y
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_LPC32XX is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_MXS is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_NOMADIK is not set
+CONFIG_ARCH_NR_GPIO=512
+# CONFIG_ARCH_NUC93X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PRIMA2 is not set
+CONFIG_ARCH_PROVIDES_UDELAY=y
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_REALVIEW is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5P64X0 is not set
+# CONFIG_ARCH_S5PC100 is not set
+# CONFIG_ARCH_S5PV210 is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_SHMOBILE is not set
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_TCC_926 is not set
+CONFIG_ARCH_TEGRA=y
+CONFIG_ARCH_TEGRA_HAS_PCIE=y
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_U8500 is not set
+# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_VEXPRESS is not set
+# CONFIG_ARCH_VT8500 is not set
+# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_ZYNQ is not set
+CONFIG_ARM=y
+CONFIG_ARM_DMA_MEM_BUFFERABLE=y
+# CONFIG_ARM_ERRATA_430973 is not set
+# CONFIG_ARM_ERRATA_458693 is not set
+# CONFIG_ARM_ERRATA_460075 is not set
+# CONFIG_ARM_ERRATA_720789 is not set
+# CONFIG_ARM_ERRATA_720791 is not set
+CONFIG_ARM_ERRATA_742230=y
+# CONFIG_ARM_ERRATA_742231 is not set
+# CONFIG_ARM_ERRATA_753970 is not set
+# CONFIG_ARM_ERRATA_754327 is not set
+CONFIG_ARM_ERRATA_764369=y
+# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set
+CONFIG_ARM_GIC=y
+CONFIG_ARM_L1_CACHE_SHIFT=5
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+CONFIG_ARM_SAVE_DEBUG_CONTEXT=y
+CONFIG_ARM_THUMB=y
+CONFIG_ARM_THUMBEE=y
+CONFIG_ARM_UNWIND=y
+# CONFIG_ATA is not set
+# CONFIG_ATH5K is not set
+# CONFIG_ATH5K_PCI is not set
+# CONFIG_ATH6K_LEGACY is not set
+# CONFIG_ATH9K is not set
+# CONFIG_ATL1 is not set
+# CONFIG_ATL1C is not set
+# CONFIG_ATL1E is not set
+# CONFIG_ATL2 is not set
+# CONFIG_AUTO_ZRELADDR is not set
+# CONFIG_AX88796 is not set
+# CONFIG_B44 is not set
+CONFIG_BACKLIGHT_PWM=y
+# CONFIG_BACKLIGHT_TEGRA_PWM is not set
+CONFIG_BATTERY_BQ20Z75=y
+# CONFIG_BCM4329 is not set
+# CONFIG_BCMDHD is not set
+# CONFIG_BE2ISCSI is not set
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_BRCMDBG is not set
+CONFIG_BRCMFMAC=m
+CONFIG_BRCMUTIL=m
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_BT_ATH3K is not set
+# CONFIG_BT_HCIBCM203X is not set
+# CONFIG_BT_HCIBPA10X is not set
+CONFIG_BT_HCIBTSDIO=m
+CONFIG_BT_HCIUART=m
+# CONFIG_BT_HCIUART_ATH3K is not set
+# CONFIG_BT_HCIUART_BCSP is not set
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_LL=y
+CONFIG_CACHE_L2X0=y
+CONFIG_CACHE_PL310=y
+CONFIG_CHARGER_GPIO=y
+# CONFIG_CHARGER_ISP1704 is not set
+CONFIG_CLKDEV_LOOKUP=y
+CONFIG_CLKSRC_MMIO=y
+CONFIG_CMDLINE="mem=448M@0M console=ttyS0,115200n8 earlyprintk init=/bin/ash"
+# CONFIG_CMDLINE_EXTEND is not set
+# CONFIG_CMDLINE_FORCE is not set
+CONFIG_CMDLINE_FROM_BOOTLOADER=y
+CONFIG_COMPAT_BRK=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_CPA=y
+# CONFIG_CPUQUIET_FRAMEWORK is not set
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_GOV_USERSPACE is not set
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_HAS_PMU=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_V7=y
+# CONFIG_CRASH_DUMP is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_DEV_TEGRA_AES is not set
+# CONFIG_DCC_TTY is not set
+# CONFIG_DEBUG_HIGHMEM is not set
+# CONFIG_DEBUG_ICEDCC is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEPRECATED_PARAM_STRUCT is not set
+# CONFIG_DM9000 is not set
+# CONFIG_DRM is not set
+CONFIG_DTC=y
+# CONFIG_E1000 is not set
+# CONFIG_E1000E is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_FB_BACKLIGHT is not set
+CONFIG_FB_TEGRA=y
+# CONFIG_FCOE is not set
+CONFIG_FIQ=y
+# CONFIG_FIQ_DEBUGGER is not set
+CONFIG_FLATMEM=y
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_FRAME_WARN=1024
+# CONFIG_FTGMAC100 is not set
+# CONFIG_FTMAC100 is not set
+CONFIG_FUNCTION_GRAPH_TRACER=y
+CONFIG_HARDIRQS_SW_RESEND=y
+# CONFIG_HARDLOCKUP_DETECTOR is not set
+CONFIG_HAVE_AOUT=y
+CONFIG_HAVE_ARCH_PFN_VALID=y
+CONFIG_HAVE_ARM_SCU=y
+CONFIG_HAVE_ARM_TWD=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_HAVE_PROC_CPU=y
+CONFIG_HAVE_PWM=y
+CONFIG_HAVE_SCHED_CLOCK=y
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_PID is not set
+CONFIG_HIGHMEM=y
+# CONFIG_HIGHPTE is not set
+# CONFIG_HOSTAP_PCI is not set
+# CONFIG_HOSTAP_PLX is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HVC_DCC is not set
+CONFIG_HW_PERF_EVENTS=y
+CONFIG_HZ=100
+# CONFIG_I2C_DESIGNWARE is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_PIIX4 is not set
+CONFIG_I2C_TEGRA=y
+# CONFIG_IGBVF is not set
+# CONFIG_INPUT_PWM_BEEPER is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
+CONFIG_IRQ_DOMAIN=y
+# CONFIG_ISCSI_BOOT_SYSFS is not set
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_IWL3945 is not set
+# CONFIG_IWL4965 is not set
+# CONFIG_IWLAGN is not set
+# CONFIG_IWM is not set
+# CONFIG_IWMC3200TOP is not set
+# CONFIG_JME is not set
+CONFIG_KEYBOARD_TEGRA=y
+CONFIG_KTIME_SCALAR=y
+CONFIG_LBDAF=y
+CONFIG_LEDS_PWM=y
+# CONFIG_LEDS_REGULATOR is not set
+# CONFIG_LIBERTAS_THINFIRM_USB is not set
+# CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
+CONFIG_LOCAL_TIMERS=y
+# CONFIG_LPC_SCH is not set
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_MACH_HAS_SND_SOC_TEGRA_WM8903=y
+# CONFIG_MACH_TEGRA_DT is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_MFD_ASIC3 is not set
+CONFIG_MFD_CORE=y
+# CONFIG_MFD_NVEC is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_MG_DISK is not set
+CONFIG_MMC=y
+# CONFIG_MMC_BKOPS is not set
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set
+CONFIG_MMC_BLOCK_MINORS=16
+# CONFIG_MMC_CB710 is not set
+# CONFIG_MMC_CLKGATE is not set
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_DW is not set
+# CONFIG_MMC_EMBEDDED_SDIO is not set
+# CONFIG_MMC_PARANOID_SD_INIT is not set
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_IO_ACCESSORS=y
+# CONFIG_MMC_SDHCI_PCI is not set
+CONFIG_MMC_SDHCI_PLTFM=y
+# CONFIG_MMC_SDHCI_PXAV2 is not set
+# CONFIG_MMC_SDHCI_PXAV3 is not set
+CONFIG_MMC_SDHCI_TEGRA=y
+# CONFIG_MMC_TEST is not set
+# CONFIG_MMC_TIFM_SD is not set
+CONFIG_MMC_UNSAFE_RESUME=y
+# CONFIG_MMC_USHC is not set
+# CONFIG_MMC_VIA_SDMMC is not set
+# CONFIG_MMC_VUB300 is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
+# CONFIG_MOUSE_PS2 is not set
+CONFIG_NEED_DMA_MAP_STATE=y
+# CONFIG_NET_PCI is not set
+# CONFIG_NON_ALIASED_COHERENT_MEM is not set
+CONFIG_NVMAP_ALLOW_SYSMEM=y
+CONFIG_NVMAP_CACHE_MAINT_BY_SET_WAYS=y
+CONFIG_NVMAP_CARVEOUT_COMPACTOR=y
+# CONFIG_NVMAP_CARVEOUT_KILLER is not set
+# CONFIG_NVMAP_HIGHMEM_ONLY is not set
+CONFIG_NVMAP_PAGE_POOLS=y
+CONFIG_NVMAP_PAGE_POOL_SIZE=0x0
+CONFIG_NVMAP_RECLAIM_UNPINNED_VM=y
+# CONFIG_NVMAP_VPR is not set
+# CONFIG_OABI_COMPAT is not set
+# CONFIG_OC_ETM is not set
+CONFIG_OF=y
+CONFIG_OF_ADDRESS=y
+CONFIG_OF_DEVICE=y
+CONFIG_OF_EARLY_FLATTREE=y
+CONFIG_OF_FLATTREE=y
+CONFIG_OF_GPIO=y
+CONFIG_OF_I2C=y
+CONFIG_OF_IRQ=y
+CONFIG_OF_MDIO=y
+CONFIG_OF_NET=y
+CONFIG_OF_PCI=y
+CONFIG_OF_PCI_IRQ=y
+CONFIG_OF_SPI=y
+CONFIG_OLD_MCOUNT=y
+CONFIG_OUTER_CACHE=y
+CONFIG_OUTER_CACHE_SYNC=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+# CONFIG_PCIEPORTBUS is not set
+CONFIG_PCI_SYSCALL=y
+CONFIG_PERF_USE_VMALLOC=y
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+# CONFIG_PL310_ERRATA_588369 is not set
+# CONFIG_PL310_ERRATA_727915 is not set
+# CONFIG_PL310_ERRATA_769419 is not set
+# CONFIG_PLAT_SPEAR is not set
+CONFIG_PM_CLK=y
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_R8169 is not set
+# CONFIG_RC_CORE is not set
+CONFIG_REGULATOR=y
+# CONFIG_REGULATOR_AD5398 is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_REGULATOR_DEBUG is not set
+# CONFIG_REGULATOR_DUMMY is not set
+# CONFIG_REGULATOR_FAN53555 is not set
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+# CONFIG_REGULATOR_GPIO is not set
+# CONFIG_REGULATOR_ISL6271A is not set
+# CONFIG_REGULATOR_LP3971 is not set
+# CONFIG_REGULATOR_LP3972 is not set
+# CONFIG_REGULATOR_MAX1586 is not set
+# CONFIG_REGULATOR_MAX8649 is not set
+# CONFIG_REGULATOR_MAX8660 is not set
+# CONFIG_REGULATOR_MAX8952 is not set
+# CONFIG_REGULATOR_MAX8973 is not set
+# CONFIG_REGULATOR_TPS6238X0 is not set
+# CONFIG_REGULATOR_TPS65023 is not set
+# CONFIG_REGULATOR_TPS6507X is not set
+# CONFIG_REGULATOR_TPS6524X is not set
+# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+CONFIG_RFKILL_GPIO=m
+# CONFIG_RFKILL_REGULATOR is not set
+# CONFIG_RT2500USB is not set
+# CONFIG_RT2800USB is not set
+# CONFIG_RT73USB is not set
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_TEGRA is not set
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTL8192CE is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_3W_SAS is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_SCSI_BFA_FC is not set
+# CONFIG_SCSI_BNX2X_FCOE is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_CXGB3_ISCSI is not set
+# CONFIG_SCSI_CXGB4_ISCSI is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_HPSA is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_IPS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_MPT2SAS is not set
+# CONFIG_SCSI_MVSAS is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_PM8001 is not set
+# CONFIG_SCSI_PMCRAID is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+CONFIG_SCSI_SCAN_ASYNC=y
+# CONFIG_SCSI_SRP is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SD8797 is not set
+# CONFIG_SDIO_UART is not set
+CONFIG_SENSORS_ISL29018=m
+# CONFIG_SENSORS_LIS3_SPI is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_EXTENDED is not set
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_PCI=y
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_OF_PLATFORM=y
+# CONFIG_SERIAL_TEGRA is not set
+# CONFIG_SERIO_PCIPS2 is not set
+# CONFIG_SKY2 is not set
+# CONFIG_SMC911X is not set
+CONFIG_SMC91X=m
+CONFIG_SMP_ON_UP=y
+# CONFIG_SMSC911X is not set
+# CONFIG_SND_ARM is not set
+# CONFIG_SND_HDA_INTEL is not set
+CONFIG_SND_PCM=y
+CONFIG_SND_SOC=y
+# CONFIG_SND_SOC_ALL_CODECS is not set
+# CONFIG_SND_SOC_CACHE_LZO is not set
+CONFIG_SND_SOC_I2C_AND_SPI=y
+CONFIG_SND_SOC_SPDIF=y
+CONFIG_SND_SOC_TEGRA=y
+CONFIG_SND_SOC_TEGRA_WM8903=y
+# CONFIG_SND_SOC_TLV320AIC326X is not set
+CONFIG_SND_SOC_WM8903=y
+CONFIG_SND_TIMER=y
+CONFIG_SOC_CAMERA=m
+# CONFIG_SOC_CAMERA_IMX074 is not set
+# CONFIG_SOC_CAMERA_MT9M001 is not set
+# CONFIG_SOC_CAMERA_MT9M111 is not set
+# CONFIG_SOC_CAMERA_MT9T031 is not set
+# CONFIG_SOC_CAMERA_MT9T112 is not set
+# CONFIG_SOC_CAMERA_MT9V022 is not set
+CONFIG_SOC_CAMERA_OV2640=m
+# CONFIG_SOC_CAMERA_OV5642 is not set
+# CONFIG_SOC_CAMERA_OV6650 is not set
+# CONFIG_SOC_CAMERA_OV772X is not set
+# CONFIG_SOC_CAMERA_OV9640 is not set
+CONFIG_SOC_CAMERA_OV9740=m
+# CONFIG_SOC_CAMERA_PLATFORM is not set
+# CONFIG_SOC_CAMERA_RJ54N1 is not set
+# CONFIG_SOC_CAMERA_TW9910 is not set
+# CONFIG_SPARSE_IRQ is not set
+# CONFIG_SPI_SLAVE_TEGRA is not set
+# CONFIG_SPI_TEGRA is not set
+CONFIG_SQUASHFS=y
+# CONFIG_SQUASHFS_EMBEDDED is not set
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+CONFIG_SQUASHFS_LZO=y
+# CONFIG_SQUASHFS_XATTR is not set
+# CONFIG_SQUASHFS_XZ is not set
+CONFIG_SQUASHFS_ZLIB=y
+# CONFIG_SSB is not set
+CONFIG_SWP_EMULATE=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+# CONFIG_TCG_TIS is not set
+# CONFIG_TEGRA_AVP is not set
+# CONFIG_TEGRA_BB_SUPPORT is not set
+# CONFIG_TEGRA_BB_XMM_POWER is not set
+# CONFIG_TEGRA_BB_XMM_POWER2 is not set
+# CONFIG_TEGRA_BPC_MGMT is not set
+CONFIG_TEGRA_CAMERA=y
+CONFIG_TEGRA_CLOCK_DEBUG_WRITE=y
+CONFIG_TEGRA_CORE_DVFS=y
+CONFIG_TEGRA_CPU_DVFS=y
+CONFIG_TEGRA_DC=y
+CONFIG_TEGRA_DC_EXTENSIONS=y
+# CONFIG_TEGRA_DEBUG_UARTC is not set
+# CONFIG_TEGRA_DEBUG_UARTD is not set
+# CONFIG_TEGRA_DEBUG_UARTE is not set
+# CONFIG_TEGRA_DEBUG_UART_NONE is not set
+# CONFIG_TEGRA_DSI is not set
+CONFIG_TEGRA_DTV=y
+CONFIG_TEGRA_EMC_SCALING_ENABLE=y
+# CONFIG_TEGRA_FIQ_DEBUGGER is not set
+# CONFIG_TEGRA_FPGA_PLATFORM is not set
+CONFIG_TEGRA_GRHOST=y
+CONFIG_TEGRA_GRHOST_DEFAULT_TIMEOUT=30000
+CONFIG_TEGRA_GRHOST_USE_NVMAP=y
+# CONFIG_TEGRA_HDMI_74MHZ_LIMIT is not set
+# CONFIG_TEGRA_IOMMU_SMMU is not set
+CONFIG_TEGRA_IOVMM=y
+# CONFIG_TEGRA_MC_PROFILE is not set
+# CONFIG_TEGRA_MEDIASERVER is not set
+CONFIG_TEGRA_NVAVP=y
+# CONFIG_TEGRA_NVAVP_AUDIO is not set
+# CONFIG_TEGRA_NVHDCP is not set
+CONFIG_TEGRA_NVMAP=y
+CONFIG_TEGRA_PWM=y
+CONFIG_TEGRA_RPC=y
+CONFIG_TEGRA_SILICON_PLATFORM=y
+# CONFIG_TEGRA_SIMULATION_PLATFORM is not set
+CONFIG_TEGRA_SYSTEM_DMA=y
+CONFIG_TEGRA_THERMAL_THROTTLE=y
+# CONFIG_TEGRA_USB_MODEM_POWER is not set
+# CONFIG_TEGRA_WDT_RECOVERY is not set
+# CONFIG_THUMB2_KERNEL is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_TORCH_SSL3250A is not set
+# CONFIG_TORCH_TPS61050 is not set
+CONFIG_TOUCHSCREEN_ATMEL_MXT=m
+# CONFIG_TOUCHSCREEN_W90X900 is not set
+# CONFIG_UACCESS_WITH_MEMCPY is not set
+CONFIG_USB_EHCI_TEGRA=y
+# CONFIG_USB_NET_DM9601 is not set
+# CONFIG_USB_NET_NET1080 is not set
+# CONFIG_USB_OHCI_HCD is not set
+CONFIG_USB_OTG_UTILS=y
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_STORAGE_REALTEK is not set
+# CONFIG_USB_TEGRA_OTG is not set
+# CONFIG_USB_UHCI_HCD is not set
+CONFIG_USB_ULPI=y
+CONFIG_USB_ULPI_VIEWPORT=y
+CONFIG_USE_OF=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+CONFIG_VGA_ARB=y
+CONFIG_VGA_ARB_MAX_GPUS=16
+CONFIG_VIDEOBUF2_CORE=m
+CONFIG_VIDEOBUF_GEN=m
+# CONFIG_VIDEO_AD5816 is not set
+# CONFIG_VIDEO_AD5820 is not set
+# CONFIG_VIDEO_AR0832 is not set
+# CONFIG_VIDEO_OV14810 is not set
+# CONFIG_VIDEO_OV2710 is not set
+# CONFIG_VIDEO_OV5640 is not set
+# CONFIG_VIDEO_OV5650 is not set
+# CONFIG_VIDEO_OV9726 is not set
+# CONFIG_VIDEO_SH532U is not set
+# CONFIG_VIDEO_SH_MOBILE_CEU is not set
+# CONFIG_VIDEO_SH_MOBILE_CSI2 is not set
+# CONFIG_VIDEO_SOC380 is not set
+# CONFIG_VIRTIO_PCI is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_XFRM_USER=m
+# CONFIG_XIP_KERNEL is not set
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_ZBOOT_ROM_TEXT=0x0
+# CONFIG_ZD1211RW is not set
+CONFIG_ZONE_DMA_FLAG=0
diff --git a/chromeos/config/armel/config.flavour.chromeos-tegra3 b/chromeos/config/armel/config.flavour.chromeos-tegra3
new file mode 100644
index 000000000000..1b6f87579921
--- /dev/null
+++ b/chromeos/config/armel/config.flavour.chromeos-tegra3
@@ -0,0 +1,124 @@
+#
+# Config options generated by splitconfig
+#
+# CONFIG_AFS_FS is not set
+# CONFIG_ANDROID_PARANOID_NETWORK is not set
+CONFIG_ARCH_SUPPORTS_MSI=y
+CONFIG_ARCH_TEGRA_3x_SOC=y
+CONFIG_ARCH_TEGRA_HAS_DUAL_3D=y
+CONFIG_ARCH_TEGRA_HAS_DUAL_CPU_CLUSTERS=y
+CONFIG_ARCH_TEGRA_HAS_SATA=y
+# CONFIG_ARM_ERRATA_716044 is not set
+CONFIG_ARM_ERRATA_743622=y
+CONFIG_ARM_ERRATA_751472=y
+CONFIG_ARM_ERRATA_752520=y
+CONFIG_ARM_ERRATA_754322=y
+CONFIG_BATTERY_BQ27X00_I2C=y
+CONFIG_BATTERY_BQ27X00_PLATFORM=y
+CONFIG_BATTERY_BQ27x00=y
+# CONFIG_CEPH_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+CONFIG_CRYPTO_CTS=y
+# CONFIG_CRYPTO_DEV_TEGRA_SE is not set
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_DNOTIFY=y
+CONFIG_DNS_RESOLVER=y
+CONFIG_EXPORTFS=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+CONFIG_GIC_SET_MULTIPLE_CPUS=y
+CONFIG_IPV6=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_MAC80211_MESH=y
+# CONFIG_MACH_ARUBA is not set
+CONFIG_MACH_CARDHU=y
+CONFIG_MACH_HAS_SND_SOC_TEGRA_MAX98095=y
+CONFIG_MACH_HAS_SND_SOC_TEGRA_TLV320AIC326X=y
+# CONFIG_MACH_KAI is not set
+# CONFIG_MACH_P1852 is not set
+# CONFIG_MACH_TEGRA_ENTERPRISE is not set
+# CONFIG_MFD_TPS6586X is not set
+CONFIG_MFD_TPS6591X=y
+# CONFIG_NCP_FS is not set
+CONFIG_NEON=y
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V3_ACL is not set
+CONFIG_NFSD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_USE_KERNEL_DNS=y
+# CONFIG_NFS_USE_LEGACY_DNS is not set
+# CONFIG_NFS_USE_NEW_IDMAPPER is not set
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
+CONFIG_NR_CPUS=4
+CONFIG_NVMAP_CONVERT_CARVEOUT_TO_IOVMM=y
+CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_PCI_MSI=y
+CONFIG_REGMAP=y
+CONFIG_REGMAP_I2C=y
+CONFIG_REGULATOR_TPS62360=y
+CONFIG_REGULATOR_TPS6591X=y
+CONFIG_REPORT_PRESENT_CPUS=y
+CONFIG_ROOT_NFS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+CONFIG_RTC_DRV_TPS6591x=y
+CONFIG_SENSORS_ISL29028=m
+CONFIG_SENSORS_NCT1008=y
+# CONFIG_SENSORS_TEGRA_TSENSOR is not set
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+CONFIG_SND_SOC_MAX98095=y
+CONFIG_SND_SOC_TEGRA30_AHUB=y
+CONFIG_SND_SOC_TEGRA30_DAM=y
+CONFIG_SND_SOC_TEGRA30_I2S=y
+CONFIG_SND_SOC_TEGRA30_SPDIF=y
+CONFIG_SND_SOC_TEGRA_MAX98095=y
+# CONFIG_SND_SOC_TEGRA_TLV320AIC326X is not set
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_SWAP=y
+CONFIG_TASK_SIZE=0x7F000000
+CONFIG_TASK_SIZE_2G_LESS_16M=y
+# CONFIG_TASK_SIZE_2G_LESS_24M is not set
+CONFIG_TEGRA_AUTO_HOTPLUG=y
+CONFIG_TEGRA_AVP_KERNEL_ON_SMMU=y
+# CONFIG_TEGRA_CARDHU_DSI is not set
+CONFIG_TEGRA_CLUSTER_CONTROL=y
+CONFIG_TEGRA_DEBUG_UARTA=y
+# CONFIG_TEGRA_DEBUG_UARTB is not set
+CONFIG_TEGRA_DYNAMIC_PWRDET=y
+CONFIG_TEGRA_EDP_EXACT_FREQ=y
+CONFIG_TEGRA_EDP_LIMITS=y
+CONFIG_TEGRA_EMC_TO_DDR_CLOCK=1
+CONFIG_TEGRA_IOVMM_SMMU=y
+# CONFIG_TEGRA_IOVMM_SMMU_SYSFS is not set
+CONFIG_TEGRA_LP2_ARM_TWD=y
+# CONFIG_TEGRA_MC_EARLY_ACK is not set
+CONFIG_TEGRA_PCI=y
+CONFIG_TEGRA_PLLM_RESTRICTED=y
+CONFIG_TEGRA_PREINIT_CLOCKS=y
+CONFIG_TEGRA_PREPOWER_WIFI=y
+CONFIG_TEGRA_SLOW_CSITE=y
+CONFIG_USB_HOTPLUG=y
+CONFIG_USB_NET_AX8817X=y
+CONFIG_USB_NET_CDCETHER=y
+CONFIG_USB_NET_CDC_NCM=y
+CONFIG_USB_NET_MCS7830=y
+CONFIG_USB_NET_SMSC95XX=y
+CONFIG_USB_USBNET=y
+CONFIG_VMSPLIT_2G=y
+# CONFIG_VMSPLIT_3G is not set
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
diff --git a/chromeos/config/armel/config.flavour.chromiumos-arm b/chromeos/config/armel/config.flavour.chromiumos-arm
new file mode 100644
index 000000000000..3cfc11bfffc9
--- /dev/null
+++ b/chromeos/config/armel/config.flavour.chromiumos-arm
@@ -0,0 +1,85 @@
+#
+# Config options generated by splitconfig
+#
+CONFIG_ANDROID_PARANOID_NETWORK=y
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+CONFIG_ARCH_TEGRA_2x_SOC=y
+# CONFIG_ARCH_TEGRA_3x_SOC is not set
+CONFIG_ARM_ERRATA_716044=y
+# CONFIG_ARM_ERRATA_743622 is not set
+# CONFIG_ARM_ERRATA_751472 is not set
+# CONFIG_ARM_ERRATA_752520 is not set
+# CONFIG_ARM_ERRATA_754322 is not set
+# CONFIG_BATTERY_BQ27x00 is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_DNS_RESOLVER is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x16=y
+CONFIG_FONT_8x8=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_GIC_SET_MULTIPLE_CPUS is not set
+CONFIG_IPV6=m
+# CONFIG_IP_PNP is not set
+# CONFIG_MAC80211_MESH is not set
+CONFIG_MACH_HARMONY=y
+CONFIG_MACH_KAEN=y
+# CONFIG_MACH_P852 is not set
+# CONFIG_MACH_PAZ00 is not set
+CONFIG_MACH_SEABOARD=y
+# CONFIG_MACH_TRIMSLICE is not set
+# CONFIG_MACH_VENTANA is not set
+CONFIG_MACH_WARIO=y
+# CONFIG_MACH_WHISTLER is not set
+CONFIG_MFD_TPS6586X=y
+# CONFIG_MFD_TPS6591X is not set
+# CONFIG_NEON is not set
+# CONFIG_NETWORK_FILESYSTEMS is not set
+CONFIG_NR_CPUS=2
+CONFIG_PAGE_OFFSET=0xC0000000
+# CONFIG_REGULATOR_TPS62360 is not set
+CONFIG_REGULATOR_TPS6586X=y
+# CONFIG_REPORT_PRESENT_CPUS is not set
+CONFIG_RTC_DRV_TPS6586X=y
+# CONFIG_SENSORS_ISL29028 is not set
+# CONFIG_SENSORS_NCT1008 is not set
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+CONFIG_SND_SOC_TEGRA20_DAS=y
+CONFIG_SND_SOC_TEGRA20_I2S=y
+CONFIG_SND_SOC_TEGRA20_SPDIF=y
+# CONFIG_SWAP is not set
+CONFIG_TASK_SIZE=0xBF000000
+CONFIG_TASK_SIZE_3G_LESS_16M=y
+# CONFIG_TASK_SIZE_3G_LESS_24M is not set
+CONFIG_TEGRA_AVP_KERNEL_ON_MMU=y
+# CONFIG_TEGRA_DEBUG_UARTA is not set
+CONFIG_TEGRA_DEBUG_UARTB=y
+# CONFIG_TEGRA_DYNAMIC_PWRDET is not set
+# CONFIG_TEGRA_EDP_LIMITS is not set
+CONFIG_TEGRA_EMC_TO_DDR_CLOCK=2
+# CONFIG_TEGRA_IOMMU_GART is not set
+CONFIG_TEGRA_IOVMM_GART=y
+# CONFIG_TEGRA_PCI is not set
+# CONFIG_TEGRA_PREINIT_CLOCKS is not set
+# CONFIG_TEGRA_PREPOWER_WIFI is not set
+# CONFIG_TEGRA_SLOW_CSITE is not set
+# CONFIG_TEGRA_STAT_MON is not set
+# CONFIG_USB_HOTPLUG is not set
+CONFIG_USB_NET_AX8817X=m
+CONFIG_USB_NET_CDCETHER=m
+CONFIG_USB_NET_CDC_NCM=m
+CONFIG_USB_NET_MCS7830=m
+CONFIG_USB_NET_SMSC95XX=m
+CONFIG_USB_USBNET=m
+# CONFIG_VIDEO_VIVI is not set
+# CONFIG_VMSPLIT_2G is not set
+CONFIG_VMSPLIT_3G=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
diff --git a/chromeos/config/config.common.chromeos b/chromeos/config/config.common.chromeos
new file mode 100644
index 000000000000..6c5db0fc665d
--- /dev/null
+++ b/chromeos/config/config.common.chromeos
@@ -0,0 +1,2042 @@
+#
+# Config options generated by splitconfig
+#
+# CONFIG_ABX500_CORE is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_ACENIC is not set
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_AD2S120X is not set
+# CONFIG_AD2S1210 is not set
+# CONFIG_AD2S90 is not set
+# CONFIG_AD525X_DPOT is not set
+# CONFIG_AD5446 is not set
+# CONFIG_AD5504 is not set
+# CONFIG_AD5624R_SPI is not set
+# CONFIG_AD5686 is not set
+# CONFIG_AD5791 is not set
+# CONFIG_AD5930 is not set
+# CONFIG_AD7150 is not set
+# CONFIG_AD7152 is not set
+# CONFIG_AD7291 is not set
+# CONFIG_AD7298 is not set
+# CONFIG_AD7314 is not set
+# CONFIG_AD7476 is not set
+# CONFIG_AD7606 is not set
+# CONFIG_AD7745 is not set
+# CONFIG_AD7780 is not set
+# CONFIG_AD7793 is not set
+# CONFIG_AD7816 is not set
+# CONFIG_AD7887 is not set
+# CONFIG_AD799X is not set
+# CONFIG_AD9832 is not set
+# CONFIG_AD9834 is not set
+# CONFIG_AD9850 is not set
+# CONFIG_AD9852 is not set
+# CONFIG_AD9910 is not set
+# CONFIG_AD9951 is not set
+# CONFIG_ADE7753 is not set
+# CONFIG_ADE7754 is not set
+# CONFIG_ADE7758 is not set
+# CONFIG_ADE7759 is not set
+# CONFIG_ADE7854 is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADIS16060 is not set
+# CONFIG_ADIS16080 is not set
+# CONFIG_ADIS16130 is not set
+# CONFIG_ADIS16201 is not set
+# CONFIG_ADIS16203 is not set
+# CONFIG_ADIS16204 is not set
+# CONFIG_ADIS16209 is not set
+# CONFIG_ADIS16220 is not set
+# CONFIG_ADIS16240 is not set
+# CONFIG_ADIS16260 is not set
+# CONFIG_ADIS16400 is not set
+# CONFIG_ADM8211 is not set
+# CONFIG_ADT7310 is not set
+# CONFIG_ADT7316 is not set
+# CONFIG_ADT7410 is not set
+# CONFIG_ADT75 is not set
+# CONFIG_ADXRS450 is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_AIO=y
+# CONFIG_ALTERA_STAPL is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ANDROID is not set
+CONFIG_ANON_INODES=y
+# CONFIG_APANIC is not set
+# CONFIG_APDS9802ALS is not set
+# CONFIG_APPLICOM is not set
+CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+# CONFIG_ARCNET is not set
+# CONFIG_ARPD is not set
+# CONFIG_ASHMEM is not set
+# CONFIG_ASUS_OLED is not set
+# CONFIG_AT76C50X_USB is not set
+# CONFIG_ATALK is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_ATH9K_HTC is not set
+CONFIG_ATH_COMMON=m
+CONFIG_ATH_DEBUG=y
+# CONFIG_ATM is not set
+# CONFIG_ATMEL is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
+# CONFIG_AUDIT is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_AUXDISPLAY is not set
+CONFIG_AVERAGE=y
+# CONFIG_B43 is not set
+# CONFIG_B43LEGACY is not set
+# CONFIG_BACKLIGHT_ADP8860 is not set
+# CONFIG_BACKLIGHT_ADP8870 is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_GENERIC=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_BACKTRACE_SELF_TEST is not set
+CONFIG_BASE_FULL=y
+CONFIG_BASE_SMALL=0
+# CONFIG_BATMAN_ADV is not set
+# CONFIG_BATTERY_DS2780 is not set
+# CONFIG_BATTERY_DS2782 is not set
+# CONFIG_BATTERY_MAX17040 is not set
+# CONFIG_BATTERY_MAX17042 is not set
+# CONFIG_BATTERY_MAX17048 is not set
+# CONFIG_BCM4329_RFKILL is not set
+# CONFIG_BCMA is not set
+CONFIG_BCMA_POSSIBLE=y
+# CONFIG_BCMDHD_CFG80211 is not set
+# CONFIG_BCMDHD_NOAPI is not set
+# CONFIG_BCMDHD_WEXT is not set
+# CONFIG_BCM_WIMAX is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+CONFIG_BINARY_PRINTF=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_BITREVERSE=y
+# CONFIG_BLK_CGROUP is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_CPQ_DA is not set
+CONFIG_BLK_DEV=y
+CONFIG_BLK_DEV_BSG=y
+# CONFIG_BLK_DEV_BSGLIB is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+CONFIG_BLK_DEV_DM=y
+# CONFIG_BLK_DEV_DRBD is not set
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_INTEGRITY is not set
+CONFIG_BLK_DEV_IO_TRACE=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_RBD is not set
+CONFIG_BLK_DEV_SD=y
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+# CONFIG_BLK_DEV_UMEM is not set
+CONFIG_BLOCK=y
+# CONFIG_BMP085 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_BONDING is not set
+# CONFIG_BOOTPARAM_HARDLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE=0
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC=y
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=1
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=1
+# CONFIG_BOOT_PRINTK_DELAY is not set
+CONFIG_BOUNCE=y
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_BRIDGE is not set
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_BT=m
+# CONFIG_BTRFS_FS is not set
+# CONFIG_BT_BLUESLEEP is not set
+CONFIG_BT_HCIBFUSB=m
+CONFIG_BT_HCIBTUSB=m
+CONFIG_BT_HCIVHCI=m
+# CONFIG_BT_L2CAP is not set
+# CONFIG_BT_MRVL is not set
+# CONFIG_BT_SCO is not set
+# CONFIG_BT_TIBLUESLEEP is not set
+CONFIG_BUG=y
+# CONFIG_C2PORT is not set
+# CONFIG_CAIF is not set
+# CONFIG_CAN is not set
+CONFIG_CAN_PM_TRACE=y
+# CONFIG_CARL9170 is not set
+# CONFIG_CASSINI is not set
+# CONFIG_CB710_CORE is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_CC_STACKPROTECTOR=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_CEPH_LIB is not set
+CONFIG_CFG80211=m
+# CONFIG_CFG80211_ALLOW_RECONNECT is not set
+CONFIG_CFG80211_DEBUGFS=y
+CONFIG_CFG80211_DEFAULT_PS=y
+# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set
+# CONFIG_CFG80211_INTERNAL_REGDB is not set
+# CONFIG_CFG80211_REG_DEBUG is not set
+CONFIG_CFG80211_WEXT=y
+CONFIG_CGROUPS=y
+# CONFIG_CGROUP_CPUACCT is not set
+# CONFIG_CGROUP_DEBUG is not set
+# CONFIG_CGROUP_DEVICE is not set
+# CONFIG_CGROUP_FREEZER is not set
+# CONFIG_CGROUP_PERF is not set
+CONFIG_CGROUP_SCHED=y
+# CONFIG_CHARGER_MAX8903 is not set
+# CONFIG_CHARGER_SMB349 is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_CLEANCACHE is not set
+# CONFIG_CNIC is not set
+# CONFIG_COMPACTION is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_CONNECTOR=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_CONTEXT_SWITCH_TRACER=y
+# CONFIG_CORDIC is not set
+# CONFIG_CPUSETS is not set
+CONFIG_CPU_FREQ=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_GOV_INTERACTIVE is not set
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+CONFIG_CPU_FREQ_TABLE=y
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_GOV_LADDER=y
+CONFIG_CPU_IDLE_GOV_MENU=y
+# CONFIG_CPU_NOTIFIER_ERROR_INJECT is not set
+CONFIG_CPU_RMAP=y
+# CONFIG_CRAMFS is not set
+CONFIG_CRC16=y
+CONFIG_CRC32=y
+CONFIG_CRC7=m
+# CONFIG_CRC8 is not set
+CONFIG_CRC_CCITT=y
+CONFIG_CRC_ITU_T=m
+CONFIG_CRC_T10DIF=m
+CONFIG_CROSS_COMPILE=""
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_AEAD=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_AUTHENC=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CCM is not set
+CONFIG_CRYPTO_CRC32C=m
+# CONFIG_CRYPTO_CTR is not set
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_DEV_HIFN_795X is not set
+CONFIG_CRYPTO_ECB=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_GHASH is not set
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_HW=y
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_LZO is not set
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_PCBC is not set
+CONFIG_CRYPTO_PCOMP2=y
+# CONFIG_CRYPTO_PCRYPT is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+CONFIG_CRYPTO_RNG2=y
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SEQIV is not set
+# CONFIG_CRYPTO_SERPENT is not set
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=m
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TEST is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_USER_API_HASH is not set
+# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
+# CONFIG_CRYPTO_VMAC is not set
+CONFIG_CRYPTO_WORKQUEUE=y
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYSTALHD is not set
+# CONFIG_CUSE is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_DCB is not set
+# CONFIG_DEBUG_ATOMIC_SLEEP is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_CREDENTIALS is not set
+CONFIG_DEBUG_DEVRES=y
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_GPIO=y
+# CONFIG_DEBUG_INFO is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
+# CONFIG_DEBUG_PER_CPU_MAPS is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_DEBUG_SECTION_MISMATCH is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DEBUG_SPINLOCK=y
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DECNET is not set
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DEFAULT_CFQ=y
+CONFIG_DEFAULT_CUBIC=y
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_HOSTNAME="(none)"
+CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_DEFAULT_MESSAGE_LOGLEVEL=5
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+# CONFIG_DEFAULT_NOOP is not set
+# CONFIG_DEFAULT_RENO is not set
+CONFIG_DEFAULT_SECURITY=""
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_DEVKMEM is not set
+CONFIG_DEVMEM=y
+CONFIG_DEVPORT=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_DL2K is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_DMA_SHARED_BUFFER is not set
+# CONFIG_DM_CRYPT is not set
+# CONFIG_DM_DEBUG is not set
+# CONFIG_DM_DELAY is not set
+# CONFIG_DM_FLAKEY is not set
+# CONFIG_DM_MIRROR is not set
+# CONFIG_DM_MULTIPATH is not set
+# CONFIG_DM_RAID is not set
+# CONFIG_DM_SNAPSHOT is not set
+# CONFIG_DM_UEVENT is not set
+# CONFIG_DM_ZERO is not set
+# CONFIG_DNET is not set
+# CONFIG_DS1682 is not set
+# CONFIG_DUMMY is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_DVB_CORE is not set
+# CONFIG_DX_SEP is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+CONFIG_DYNAMIC_FTRACE=y
+CONFIG_EARLY_PRINTK=y
+# CONFIG_EASYCAP is not set
+# CONFIG_ECHO is not set
+# CONFIG_ECONET is not set
+CONFIG_ECRYPT_FS=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_EEPROM_93XX46 is not set
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+CONFIG_EFI_PARTITION=y
+# CONFIG_EFS_FS is not set
+CONFIG_ELF_CORE=y
+CONFIG_EMBEDDED=y
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_ENC28J60 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+CONFIG_EPOLL=y
+# CONFIG_EQUALIZER is not set
+# CONFIG_ET131X is not set
+# CONFIG_ETHOC is not set
+CONFIG_EVENTFD=y
+CONFIG_EVENT_POWER_TRACING_DEPRECATED=y
+CONFIG_EVENT_TRACING=y
+CONFIG_EXPERIMENTAL=y
+CONFIG_EXPERT=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_DEFAULTS_TO_ORDERED=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT4_DEBUG is not set
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_EXT4_FS_XATTR=y
+# CONFIG_EZX_PCAP is not set
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_FANOTIFY is not set
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_FAT_FS=m
+# CONFIG_FAULT_INJECTION is not set
+CONFIG_FB=y
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_ARK is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+# CONFIG_FB_BROADSHEET is not set
+# CONFIG_FB_CARMINE is not set
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_KYRO is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_METRONOME is not set
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_NVIDIA is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_PM3 is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_S3 is not set
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_SM7XX is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_TMIO is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_UDL is not set
+# CONFIG_FB_UVESA is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_VT8623 is not set
+# CONFIG_FB_WMT_GE_ROPS is not set
+# CONFIG_FB_XGI is not set
+# CONFIG_FDDI is not set
+# CONFIG_FHANDLE is not set
+CONFIG_FILE_LOCKING=y
+# CONFIG_FIREWIRE is not set
+# CONFIG_FIREWIRE_NOSY is not set
+# CONFIG_FIRMWARE_EDID is not set
+CONFIG_FIRMWARE_IN_KERNEL=y
+# CONFIG_FIXED_PHY is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FREEZER=y
+# CONFIG_FSCACHE is not set
+CONFIG_FSNOTIFY=y
+CONFIG_FS_MBCACHE=y
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_FT1000 is not set
+CONFIG_FTRACE=y
+CONFIG_FTRACE_MCOUNT_RECORD=y
+# CONFIG_FTRACE_STARTUP_TEST is not set
+# CONFIG_FUNCTION_PROFILER is not set
+CONFIG_FUNCTION_TRACER=y
+CONFIG_FUSE_FS=m
+# CONFIG_FUSION is not set
+CONFIG_FUTEX=y
+CONFIG_FW_LOADER=y
+# CONFIG_GAMEPORT is not set
+# CONFIG_GCOV_KERNEL is not set
+CONFIG_GENERIC_ACL=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_TRACER=y
+# CONFIG_GFS2_FS is not set
+CONFIG_GPIOLIB=y
+# CONFIG_GPIO_74X164 is not set
+# CONFIG_GPIO_ADP5588 is not set
+# CONFIG_GPIO_BT8XX is not set
+# CONFIG_GPIO_GENERIC_PLATFORM is not set
+# CONFIG_GPIO_IT8761E is not set
+# CONFIG_GPIO_MAX7300 is not set
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_MC33880 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_ML_IOH is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+# CONFIG_GPIO_RDC321X is not set
+# CONFIG_GPIO_SX150X is not set
+CONFIG_GPIO_SYSFS=y
+# CONFIG_GPIO_VX855 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_HAPPYMEAL is not set
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_GENERIC_HARDIRQS=y
+CONFIG_HAVE_HW_BREAKPOINT=y
+CONFIG_HAVE_IDE=y
+CONFIG_HAVE_IRQ_WORK=y
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
+CONFIG_HAVE_SPARSE_IRQ=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_HERMES is not set
+CONFIG_HFSPLUS_FS=m
+# CONFIG_HFS_FS is not set
+CONFIG_HID=y
+CONFIG_HIDRAW=y
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_ACRUX is not set
+CONFIG_HID_APPLE=m
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_EMS_FF is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_HOLTEK is not set
+# CONFIG_HID_KENSINGTON is not set
+# CONFIG_HID_KEYTOUCH is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_LCPOWER is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MONTEREY is not set
+CONFIG_HID_MULTITOUCH=m
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_ORTEK is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_PICOLCD is not set
+# CONFIG_HID_PRODIKEYS is not set
+# CONFIG_HID_QUANTA is not set
+# CONFIG_HID_ROCCAT is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SPEEDLINK is not set
+# CONFIG_HID_SUNPLUS is not set
+CONFIG_HID_SUPPORT=y
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_TWINHAN is not set
+# CONFIG_HID_UCLOGIC is not set
+# CONFIG_HID_WALTOP is not set
+# CONFIG_HID_ZEROPLUS is not set
+# CONFIG_HID_ZYDACRON is not set
+CONFIG_HIGH_RES_TIMERS=y
+# CONFIG_HIPPI is not set
+# CONFIG_HMC6352 is not set
+CONFIG_HOSTAP=m
+CONFIG_HOSTAP_FIRMWARE=y
+CONFIG_HOSTAP_FIRMWARE_NVRAM=y
+CONFIG_HOTPLUG=y
+CONFIG_HOTPLUG_CPU=y
+# CONFIG_HP100 is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_HP_ILO is not set
+# CONFIG_HTC_I2CPLD is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_DEBUG_CHIP is not set
+# CONFIG_HWMON_VID is not set
+CONFIG_HW_CONSOLE=y
+CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+CONFIG_I2C=y
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_COMPAT=y
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DIOLAN_U2C is not set
+# CONFIG_I2C_EG20T is not set
+# CONFIG_I2C_GPIO is not set
+CONFIG_I2C_HELPER_AUTO=y
+# CONFIG_I2C_INTEL_MID is not set
+# CONFIG_I2C_ISCH is not set
+# CONFIG_I2C_MUX is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_PXA_PCI is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_SLAVE is not set
+CONFIG_I2C_STUB=m
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_XILINX is not set
+# CONFIG_I2O is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_IDE is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_IGB is not set
+CONFIG_IIO=m
+# CONFIG_IIO_RING_BUFFER is not set
+# CONFIG_IIO_TRIGGER is not set
+CONFIG_IKCONFIG=m
+CONFIG_IKCONFIG_PROC=y
+# CONFIG_IMA is not set
+CONFIG_INET=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_INET6_TUNNEL is not set
+CONFIG_INET6_XFRM_MODE_BEET=m
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+# CONFIG_INET6_XFRM_TUNNEL is not set
+CONFIG_INET_AH=m
+# CONFIG_INET_DIAG is not set
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_LRO=y
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_XFRM_MODE_BEET=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=m
+CONFIG_INET_XFRM_MODE_TUNNEL=m
+CONFIG_INET_XFRM_TUNNEL=m
+# CONFIG_INFINIBAND is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_INIT_ENV_ARG_LIMIT=32
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+# CONFIG_INLINE_READ_UNLOCK is not set
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+# CONFIG_INLINE_READ_UNLOCK_IRQ is not set
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_UNLOCK is not set
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+# CONFIG_INLINE_WRITE_UNLOCK is not set
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+CONFIG_INOTIFY_USER=y
+CONFIG_INPUT=y
+# CONFIG_INPUT_AD714X is not set
+# CONFIG_INPUT_ADXL34X is not set
+# CONFIG_INPUT_ALPS_GPIO_SCROLLWHEEL is not set
+# CONFIG_INPUT_ATI_REMOTE is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_CAPELLA_CM3217 is not set
+# CONFIG_INPUT_CM109 is not set
+# CONFIG_INPUT_CMA3000 is not set
+# CONFIG_INPUT_EVBUG is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_GPIO is not set
+# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_JOYSTICK is not set
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_INPUT_KEYCHORD is not set
+# CONFIG_INPUT_KEYRESET is not set
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_KXTJ9 is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_MMA8450 is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_MPU3050 is not set
+# CONFIG_INPUT_PCF8574 is not set
+CONFIG_INPUT_POLLDEV=y
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_INPUT_UINPUT is not set
+# CONFIG_INPUT_YEALINK is not set
+# CONFIG_INTEL_MID_PTI is not set
+CONFIG_INV_SENSORS=y
+CONFIG_INV_SENSORS_ACCELEROMETERS=y
+CONFIG_INV_SENSORS_COMPASS=y
+CONFIG_INV_SENSORS_PRESSURE=y
+CONFIG_IOMMU_SUPPORT=y
+# CONFIG_ION is not set
+CONFIG_IOSCHED_CFQ=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IP1000 is not set
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+# CONFIG_IP6_NF_TARGET_REJECT_SKERR is not set
+CONFIG_IPC_NS=y
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPV6_MIP6 is not set
+# CONFIG_IPV6_MROUTE is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+CONFIG_IPV6_NDISC_NODETYPE=y
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+CONFIG_IPV6_PRIVACY=y
+# CONFIG_IPV6_ROUTER_PREF is not set
+CONFIG_IPV6_SIT=m
+# CONFIG_IPV6_SIT_6RD is not set
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPW2100 is not set
+# CONFIG_IPW2200 is not set
+# CONFIG_IPX is not set
+CONFIG_IP_ADVANCED_ROUTER=y
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_FIB_TRIE_STATS is not set
+CONFIG_IP_MROUTE=y
+# CONFIG_IP_MROUTE_MULTIPLE_TABLES is not set
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_MULTIPLE_TABLES is not set
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_TARGET_LOG=y
+CONFIG_IP_NF_TARGET_REJECT=y
+# CONFIG_IP_NF_TARGET_REJECT_SKERR is not set
+CONFIG_IP_NF_TARGET_ULOG=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+# CONFIG_IP_SCTP is not set
+# CONFIG_IP_SET is not set
+# CONFIG_IP_VS is not set
+# CONFIG_IRDA is not set
+# CONFIG_IRQSOFF_TRACER is not set
+CONFIG_IRQ_WORK=y
+# CONFIG_ISDN is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_ISL29020 is not set
+CONFIG_ISO9660_FS=m
+CONFIG_JBD=y
+CONFIG_JBD2=y
+# CONFIG_JBD2_DEBUG is not set
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_JFS_FS is not set
+CONFIG_JOLIET=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KARMA_PARTITION is not set
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_LZMA is not set
+# CONFIG_KERNEL_LZO is not set
+# CONFIG_KEXEC is not set
+# CONFIG_KEYBOARD_ADP5588 is not set
+# CONFIG_KEYBOARD_ADP5589 is not set
+CONFIG_KEYBOARD_ATKBD=y
+CONFIG_KEYBOARD_GPIO=y
+# CONFIG_KEYBOARD_GPIO_POLLED is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_LM8323 is not set
+# CONFIG_KEYBOARD_MATRIX is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
+# CONFIG_KEYBOARD_MCS is not set
+# CONFIG_KEYBOARD_MPR121 is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_QT1070 is not set
+# CONFIG_KEYBOARD_QT2160 is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_TCA6416 is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+CONFIG_KEYS=y
+CONFIG_KEYS_DEBUG_PROC_KEYS=y
+# CONFIG_KGDB is not set
+# CONFIG_KPROBES is not set
+# CONFIG_KS8851 is not set
+# CONFIG_KS8851_MLL is not set
+# CONFIG_KSM is not set
+# CONFIG_KXSD9 is not set
+# CONFIG_L2TP is not set
+# CONFIG_LAPB is not set
+# CONFIG_LCD_CLASS_DEVICE is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_LEDS_BD2802 is not set
+CONFIG_LEDS_CLASS=y
+# CONFIG_LEDS_DAC124S085 is not set
+# CONFIG_LEDS_GPIO is not set
+# CONFIG_LEDS_LM3530 is not set
+# CONFIG_LEDS_LP3944 is not set
+# CONFIG_LEDS_LP5521 is not set
+# CONFIG_LEDS_LP5523 is not set
+# CONFIG_LEDS_LT3593 is not set
+# CONFIG_LEDS_PCA9532 is not set
+# CONFIG_LEDS_PCA955X is not set
+CONFIG_LEDS_TRIGGERS=y
+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
+# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
+# CONFIG_LEDS_TRIGGER_GPIO is not set
+# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
+# CONFIG_LEDS_TRIGGER_TIMER is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_LIB80211=m
+CONFIG_LIB80211_CRYPT_CCMP=m
+CONFIG_LIB80211_CRYPT_TKIP=m
+CONFIG_LIB80211_CRYPT_WEP=m
+# CONFIG_LIB80211_DEBUG is not set
+CONFIG_LIBCRC32C=m
+# CONFIG_LIBERTAS is not set
+CONFIG_LIBERTAS_THINFIRM=m
+# CONFIG_LIBERTAS_THINFIRM_DEBUG is not set
+# CONFIG_LINE6_USB is not set
+# CONFIG_LIS3L02DQ is not set
+# CONFIG_LKDTM is not set
+# CONFIG_LLC2 is not set
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_LOCKUP_DETECTOR=y
+# CONFIG_LOCK_STAT is not set
+# CONFIG_LOGFS is not set
+# CONFIG_LOGO is not set
+CONFIG_LOG_BUF_SHIFT=18
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_LXT_PHY is not set
+CONFIG_MAC80211=m
+CONFIG_MAC80211_DEBUGFS=y
+# CONFIG_MAC80211_DEBUG_MENU is not set
+CONFIG_MAC80211_HAS_RC=y
+CONFIG_MAC80211_HWSIM=m
+CONFIG_MAC80211_LEDS=y
+CONFIG_MAC80211_RC_DEFAULT="minstrel_ht"
+CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y
+CONFIG_MAC80211_RC_MINSTREL=y
+CONFIG_MAC80211_RC_MINSTREL_HT=y
+# CONFIG_MAC80211_RC_PID is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_MAX1363 is not set
+# CONFIG_MAX517 is not set
+CONFIG_MD=y
+# CONFIG_MDIO_BITBANG is not set
+# CONFIG_MEDIA_ATTACH is not set
+# CONFIG_MEDIA_CONTROLLER is not set
+CONFIG_MEDIA_SUPPORT=m
+CONFIG_MEDIA_TUNER=m
+# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+CONFIG_MEDIA_TUNER_MC44S803=m
+CONFIG_MEDIA_TUNER_MT20XX=m
+CONFIG_MEDIA_TUNER_SIMPLE=m
+CONFIG_MEDIA_TUNER_TDA18271=m
+CONFIG_MEDIA_TUNER_TDA827X=m
+CONFIG_MEDIA_TUNER_TDA8290=m
+CONFIG_MEDIA_TUNER_TDA9887=m
+CONFIG_MEDIA_TUNER_TEA5761=m
+CONFIG_MEDIA_TUNER_TEA5767=m
+CONFIG_MEDIA_TUNER_XC2028=m
+CONFIG_MEDIA_TUNER_XC4000=m
+CONFIG_MEDIA_TUNER_XC5000=m
+# CONFIG_MEMSTICK is not set
+# CONFIG_MFD_88PM860X is not set
+# CONFIG_MFD_AAT2870_CORE is not set
+# CONFIG_MFD_JANZ_CMODIO is not set
+# CONFIG_MFD_MAX77663 is not set
+# CONFIG_MFD_MAX8907C is not set
+# CONFIG_MFD_MAX8925 is not set
+# CONFIG_MFD_MAX8997 is not set
+# CONFIG_MFD_MAX8998 is not set
+# CONFIG_MFD_MC13XXX is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_RC5T583 is not set
+# CONFIG_MFD_RDC321X is not set
+# CONFIG_MFD_RICOH583 is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_STMPE is not set
+CONFIG_MFD_SUPPORT=y
+# CONFIG_MFD_TC3589X is not set
+# CONFIG_MFD_TIMBERDALE is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_TPS65090 is not set
+# CONFIG_MFD_TPS65910 is not set
+# CONFIG_MFD_TPS65912_I2C is not set
+# CONFIG_MFD_TPS65912_SPI is not set
+# CONFIG_MFD_TPS80031 is not set
+# CONFIG_MFD_VX855 is not set
+# CONFIG_MFD_WL1273_CORE is not set
+# CONFIG_MFD_WM831X_I2C is not set
+# CONFIG_MFD_WM831X_SPI is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8994 is not set
+# CONFIG_MICREL_PHY is not set
+CONFIG_MII=y
+# CONFIG_MINIX_FS is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+CONFIG_MISC_DEVICES=y
+CONFIG_MISC_FILESYSTEMS=y
+CONFIG_MMU=y
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MOUSE_BCM5974 is not set
+# CONFIG_MOUSE_GPIO is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_SYNAPTICS_I2C is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_MPU_SENSORS_AK8963 is not set
+# CONFIG_MPU_SENSORS_AK8972 is not set
+# CONFIG_MPU_SENSORS_AK8975 is not set
+# CONFIG_MPU_SENSORS_AMI306 is not set
+# CONFIG_MPU_SENSORS_AMI30X is not set
+# CONFIG_MPU_SENSORS_BMA085 is not set
+# CONFIG_MPU_SENSORS_HMC5883 is not set
+# CONFIG_MPU_SENSORS_HSCDTD002B is not set
+# CONFIG_MPU_SENSORS_HSCDTD004A is not set
+# CONFIG_MPU_SENSORS_LSM303DLX_M is not set
+# CONFIG_MPU_SENSORS_MMC314X is not set
+# CONFIG_MPU_SENSORS_MMC314XMS is not set
+# CONFIG_MPU_SENSORS_MPU3050 is not set
+# CONFIG_MPU_SENSORS_MPU6050A2 is not set
+# CONFIG_MPU_SENSORS_MPU6050B1 is not set
+# CONFIG_MPU_SENSORS_TIMERIRQ is not set
+# CONFIG_MPU_SENSORS_YAS530 is not set
+# CONFIG_MPU_USERSPACE_DEBUG is not set
+# CONFIG_MSDOS_FS is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_MTD is not set
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+# CONFIG_MWIFIEX is not set
+# CONFIG_MWL8K is not set
+CONFIG_NAMESPACES=y
+# CONFIG_NATIONAL_PHY is not set
+CONFIG_NET=y
+# CONFIG_NETCONSOLE is not set
+CONFIG_NETDEVICES=y
+CONFIG_NETDEV_1000=y
+# CONFIG_NETDEV_10000 is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_ADVANCED is not set
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_NETFILTER_NETLINK=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NETFILTER_XTABLES=y
+CONFIG_NETFILTER_XT_MARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
+CONFIG_NETFILTER_XT_TARGET_SECMARK=y
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
+# CONFIG_NETLABEL is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
+CONFIG_NETWORK_SECMARK=y
+# CONFIG_NET_9P is not set
+CONFIG_NET_ACTIVITY_STATS=y
+# CONFIG_NET_CLS_ACT is not set
+# CONFIG_NET_CLS_BASIC is not set
+# CONFIG_NET_CLS_CGROUP is not set
+# CONFIG_NET_CLS_FLOW is not set
+# CONFIG_NET_CLS_FW is not set
+# CONFIG_NET_CLS_ROUTE4 is not set
+# CONFIG_NET_CLS_RSVP is not set
+# CONFIG_NET_CLS_RSVP6 is not set
+# CONFIG_NET_CLS_TCINDEX is not set
+# CONFIG_NET_CLS_U32 is not set
+# CONFIG_NET_DROP_MONITOR is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_NET_EMATCH is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_NET_FC is not set
+# CONFIG_NET_IPGRE_DEMUX is not set
+# CONFIG_NET_IPIP is not set
+CONFIG_NET_KEY=m
+# CONFIG_NET_KEY_MIGRATE is not set
+# CONFIG_NET_NS is not set
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+CONFIG_NET_SCHED=y
+# CONFIG_NET_SCH_CBQ is not set
+# CONFIG_NET_SCH_CHOKE is not set
+# CONFIG_NET_SCH_DRR is not set
+# CONFIG_NET_SCH_DSMARK is not set
+CONFIG_NET_SCH_FIFO=y
+# CONFIG_NET_SCH_GRED is not set
+# CONFIG_NET_SCH_HFSC is not set
+# CONFIG_NET_SCH_HTB is not set
+# CONFIG_NET_SCH_MQPRIO is not set
+# CONFIG_NET_SCH_MULTIQ is not set
+# CONFIG_NET_SCH_NETEM is not set
+# CONFIG_NET_SCH_PRIO is not set
+# CONFIG_NET_SCH_QFQ is not set
+# CONFIG_NET_SCH_RED is not set
+# CONFIG_NET_SCH_SFB is not set
+# CONFIG_NET_SCH_SFQ is not set
+# CONFIG_NET_SCH_TBF is not set
+# CONFIG_NET_SCH_TEQL is not set
+# CONFIG_NET_TULIP is not set
+# CONFIG_NET_VENDOR_3COM is not set
+CONFIG_NEW_LEDS=y
+# CONFIG_NFC is not set
+CONFIG_NF_CONNTRACK=y
+# CONFIG_NF_CONNTRACK_FTP is not set
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_NF_CONNTRACK_IPV6=m
+# CONFIG_NF_CONNTRACK_IRC is not set
+CONFIG_NF_CONNTRACK_PROC_COMPAT=y
+# CONFIG_NF_CONNTRACK_SECMARK is not set
+# CONFIG_NF_CONNTRACK_SIP is not set
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NF_DEFRAG_IPV4=y
+CONFIG_NF_DEFRAG_IPV6=m
+# CONFIG_NF_NAT is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_NL80211_TESTMODE=y
+CONFIG_NLATTR=y
+CONFIG_NLS=y
+CONFIG_NLS_ASCII=m
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_CODEPAGE_437=m
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_ISO8859_1=m
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=m
+CONFIG_NOP_TRACER=y
+# CONFIG_NOP_USB_XCEIV is not set
+# CONFIG_NOZOMI is not set
+CONFIG_NO_HZ=y
+# CONFIG_NS83820 is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_N_GSM is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_OPROFILE is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_P54_COMMON is not set
+CONFIG_PACKET=y
+CONFIG_PANIC_TIMEOUT=0
+# CONFIG_PARPORT is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_PCCARD is not set
+# CONFIG_PCH_GBE is not set
+# CONFIG_PCH_PHUB is not set
+CONFIG_PCI=y
+# CONFIG_PCI_DEBUG is not set
+# CONFIG_PCI_IOV is not set
+CONFIG_PCI_QUIRKS=y
+# CONFIG_PCI_STUB is not set
+# CONFIG_PDA_POWER is not set
+# CONFIG_PERF_COUNTERS is not set
+CONFIG_PERF_EVENTS=y
+# CONFIG_PHANTOM is not set
+# CONFIG_PHONE is not set
+# CONFIG_PHONET is not set
+CONFIG_PHYLIB=y
+CONFIG_PID_NS=y
+CONFIG_PM=y
+# CONFIG_PMBUS is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_PM_ADVANCED_DEBUG is not set
+CONFIG_PM_DEBUG=y
+CONFIG_PM_RUNTIME=y
+CONFIG_PM_SLEEP=y
+CONFIG_PM_SLEEP_SMP=y
+# CONFIG_PM_TEST_SUSPEND is not set
+# CONFIG_POHMELFS is not set
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_POWER_SUPPLY=y
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+CONFIG_PPP=m
+# CONFIG_PPPOE is not set
+# CONFIG_PPPOLAC is not set
+# CONFIG_PPPOPNS is not set
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_MPPE is not set
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPS is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_RCU is not set
+CONFIG_PREEMPT_VOLUNTARY=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_PRINTK=y
+CONFIG_PRINTK_TIME=y
+# CONFIG_PRISM2_USB is not set
+# CONFIG_PRISM54 is not set
+CONFIG_PROC_EVENTS=y
+CONFIG_PROC_FS=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_PROC_SYSCTL=y
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+CONFIG_PROFILING=y
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_PSTORE is not set
+# CONFIG_QLA3XXX is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_QUOTACTL is not set
+# CONFIG_R3964 is not set
+# CONFIG_R8187SE is not set
+# CONFIG_R8712U is not set
+# CONFIG_RADIO_ADAPTERS is not set
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_RAMOOPS is not set
+# CONFIG_RAW_DRIVER is not set
+CONFIG_RCU_CPU_STALL_TIMEOUT=60
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_RCU_FAST_NO_HZ is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_TRACE is not set
+# CONFIG_RDS is not set
+# CONFIG_RD_BZIP2 is not set
+CONFIG_RD_GZIP=y
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_LZO is not set
+# CONFIG_RD_XZ is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_REISERFS_FS is not set
+CONFIG_RELAY=y
+# CONFIG_RESOURCE_COUNTERS is not set
+CONFIG_RFKILL=y
+# CONFIG_RFKILL_INPUT is not set
+CONFIG_RFKILL_LEDS=y
+CONFIG_RFKILL_PM=y
+CONFIG_RFS_ACCEL=y
+CONFIG_RING_BUFFER=y
+# CONFIG_RING_BUFFER_BENCHMARK is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_RPS=y
+# CONFIG_RT2400PCI is not set
+# CONFIG_RT2500PCI is not set
+# CONFIG_RT2800PCI is not set
+CONFIG_RT2X00=m
+# CONFIG_RT61PCI is not set
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_DEBUG is not set
+# CONFIG_RTC_DRV_BQ32K is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1390 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_DS3232 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_EM3027 is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_ISL12022 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_M41T93 is not set
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_MSM6242 is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RP5C01 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_RV3029C2 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_TEST is not set
+# CONFIG_RTC_DRV_V3020 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+CONFIG_RTC_INTF_ALARM=y
+CONFIG_RTC_INTF_ALARM_DEV=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_LIB=y
+# CONFIG_RTL8180 is not set
+# CONFIG_RTL8187 is not set
+# CONFIG_RTL8192CU is not set
+# CONFIG_RTL8192DE is not set
+# CONFIG_RTL8192E is not set
+# CONFIG_RTL8192SE is not set
+# CONFIG_RTL8192U is not set
+# CONFIG_RTS_PSTOR is not set
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_SAMPLES is not set
+CONFIG_SCHEDSTATS=y
+# CONFIG_SCHED_AUTOGROUP is not set
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_SCHED_TRACER is not set
+CONFIG_SCSI=y
+# CONFIG_SCSI_DH is not set
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_LOGGING is not set
+CONFIG_SCSI_MOD=y
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+CONFIG_SCSI_PROC_FS=y
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+CONFIG_SCSI_SPI_ATTRS=y
+# CONFIG_SCSI_SRP_ATTRS is not set
+# CONFIG_SCSI_TGT is not set
+CONFIG_SCSI_WAIT_SCAN=m
+CONFIG_SECCOMP=y
+CONFIG_SECURITY=y
+CONFIG_SECURITYFS=y
+# CONFIG_SECURITY_APPARMOR is not set
+# CONFIG_SECURITY_DMESG_RESTRICT is not set
+CONFIG_SECURITY_NETWORK=y
+# CONFIG_SECURITY_NETWORK_XFRM is not set
+# CONFIG_SECURITY_PATH is not set
+# CONFIG_SECURITY_TOMOYO is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+# CONFIG_SENSORS_AD7414 is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADCXX is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADS1015 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_ADS7871 is not set
+# CONFIG_SENSORS_ADT7411 is not set
+# CONFIG_SENSORS_ADT7461 is not set
+# CONFIG_SENSORS_ADT7462 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7475 is not set
+# CONFIG_SENSORS_AK8975 is not set
+# CONFIG_SENSORS_AMC6821 is not set
+# CONFIG_SENSORS_APDS990X is not set
+# CONFIG_SENSORS_ASC7621 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_BH1770 is not set
+# CONFIG_SENSORS_BH1780 is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_DS620 is not set
+# CONFIG_SENSORS_EMC1403 is not set
+# CONFIG_SENSORS_EMC2103 is not set
+# CONFIG_SENSORS_EMC6W201 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_G760A is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_GPIO_FAN is not set
+# CONFIG_SENSORS_HMC5843 is not set
+# CONFIG_SENSORS_I5K_AMB is not set
+# CONFIG_SENSORS_INA219 is not set
+# CONFIG_SENSORS_INA230 is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_JC42 is not set
+# CONFIG_SENSORS_LINEAGE is not set
+# CONFIG_SENSORS_LIS3LV02D is not set
+# CONFIG_SENSORS_LIS3_I2C is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM70 is not set
+# CONFIG_SENSORS_LM73 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_LM95241 is not set
+# CONFIG_SENSORS_LM95245 is not set
+# CONFIG_SENSORS_LTC4151 is not set
+# CONFIG_SENSORS_LTC4215 is not set
+# CONFIG_SENSORS_LTC4245 is not set
+# CONFIG_SENSORS_LTC4261 is not set
+# CONFIG_SENSORS_LTR558 is not set
+# CONFIG_SENSORS_MAX1111 is not set
+# CONFIG_SENSORS_MAX16065 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX1668 is not set
+# CONFIG_SENSORS_MAX6639 is not set
+# CONFIG_SENSORS_MAX6642 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_NTC_THERMISTOR is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_SCH5627 is not set
+# CONFIG_SENSORS_SCH5636 is not set
+# CONFIG_SENSORS_SCH56XX_COMMON is not set
+# CONFIG_SENSORS_SHT15 is not set
+# CONFIG_SENSORS_SHT21 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMM665 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP102 is not set
+# CONFIG_SENSORS_TMP401 is not set
+# CONFIG_SENSORS_TMP421 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+CONFIG_SENSORS_TSL2563=m
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_VT8231 is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83795 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83L786NG is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+# CONFIG_SERIAL_IFX6X60 is not set
+# CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_MAX3100 is not set
+# CONFIG_SERIAL_MAX3107 is not set
+# CONFIG_SERIAL_MFD_HSU is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_SERIAL_PCH_UART is not set
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_XILINX_PS_UART is not set
+CONFIG_SERIO=y
+# CONFIG_SERIO_ALTERA_PS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_PS2MULT is not set
+CONFIG_SERIO_RAW=y
+CONFIG_SERIO_SERPORT=m
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_SGI_PARTITION is not set
+CONFIG_SHMEM=y
+CONFIG_SIGNALFD=y
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+CONFIG_SLABINFO=y
+CONFIG_SLHC=m
+# CONFIG_SLIP is not set
+# CONFIG_SLOB is not set
+CONFIG_SMP=y
+# CONFIG_SMSC_PHY is not set
+CONFIG_SND=y
+# CONFIG_SND_AD1889 is not set
+# CONFIG_SND_ALI5451 is not set
+# CONFIG_SND_ALOOP is not set
+# CONFIG_SND_ALS300 is not set
+# CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_ATIIXP_MODEM is not set
+# CONFIG_SND_AU8810 is not set
+# CONFIG_SND_AU8820 is not set
+# CONFIG_SND_AU8830 is not set
+# CONFIG_SND_AW2 is not set
+# CONFIG_SND_AZT3328 is not set
+# CONFIG_SND_BT87X is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_CS4281 is not set
+# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_CS5535AUDIO is not set
+# CONFIG_SND_CTXFI is not set
+# CONFIG_SND_DARLA20 is not set
+# CONFIG_SND_DARLA24 is not set
+# CONFIG_SND_DEBUG is not set
+CONFIG_SND_DRIVERS=y
+# CONFIG_SND_DUMMY is not set
+CONFIG_SND_DYNAMIC_MINORS=y
+# CONFIG_SND_ECHO3G is not set
+# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_EMU10K1X is not set
+# CONFIG_SND_EMU10K1_SEQ is not set
+# CONFIG_SND_ENS1370 is not set
+# CONFIG_SND_ENS1371 is not set
+# CONFIG_SND_ES1938 is not set
+# CONFIG_SND_ES1968 is not set
+# CONFIG_SND_FM801 is not set
+# CONFIG_SND_GINA20 is not set
+# CONFIG_SND_GINA24 is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
+CONFIG_SND_HRTIMER=m
+CONFIG_SND_HWDEP=m
+# CONFIG_SND_ICE1712 is not set
+# CONFIG_SND_ICE1724 is not set
+# CONFIG_SND_INDIGO is not set
+# CONFIG_SND_INDIGODJ is not set
+# CONFIG_SND_INDIGODJX is not set
+# CONFIG_SND_INDIGOIO is not set
+# CONFIG_SND_INDIGOIOX is not set
+# CONFIG_SND_INTEL8X0 is not set
+# CONFIG_SND_INTEL8X0M is not set
+CONFIG_SND_JACK=y
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_LAYLA20 is not set
+# CONFIG_SND_LAYLA24 is not set
+# CONFIG_SND_LOLA is not set
+# CONFIG_SND_LX6464ES is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_MIA is not set
+# CONFIG_SND_MIXART is not set
+CONFIG_SND_MIXER_OSS=m
+# CONFIG_SND_MONA is not set
+# CONFIG_SND_MPU401 is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_OPL3_LIB_SEQ is not set
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+CONFIG_SND_OSSEMUL=y
+# CONFIG_SND_OXYGEN is not set
+CONFIG_SND_PCI=y
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_PCXHR is not set
+CONFIG_SND_RAWMIDI=m
+CONFIG_SND_RAWMIDI_SEQ=m
+# CONFIG_SND_RIPTIDE is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
+# CONFIG_SND_SBAWE_SEQ is not set
+CONFIG_SND_SEQUENCER=m
+CONFIG_SND_SEQUENCER_OSS=y
+CONFIG_SND_SEQ_DUMMY=m
+CONFIG_SND_SEQ_HRTIMER_DEFAULT=y
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_SPI is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+# CONFIG_SND_TRIDENT is not set
+CONFIG_SND_USB=y
+# CONFIG_SND_USB_6FIRE is not set
+CONFIG_SND_USB_AUDIO=m
+# CONFIG_SND_USB_CAIAQ is not set
+# CONFIG_SND_USB_UA101 is not set
+# CONFIG_SND_VERBOSE_PRINTK is not set
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VIA82XX_MODEM is not set
+# CONFIG_SND_VIRMIDI is not set
+# CONFIG_SND_VIRTUOSO is not set
+# CONFIG_SND_VX222 is not set
+# CONFIG_SND_YMFPCI is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_SOLO6X10 is not set
+CONFIG_SOUND=y
+CONFIG_SOUND_OSS_CORE=y
+CONFIG_SOUND_OSS_CORE_PRECLAIM=y
+# CONFIG_SOUND_PRIME is not set
+# CONFIG_SPARSE_RCU_POINTER is not set
+# CONFIG_SPEAKUP is not set
+CONFIG_SPI=y
+# CONFIG_SPI_ALTERA is not set
+CONFIG_SPI_BITBANG=m
+# CONFIG_SPI_DEBUG is not set
+# CONFIG_SPI_DESIGNWARE is not set
+# CONFIG_SPI_GPIO is not set
+CONFIG_SPI_MASTER=y
+# CONFIG_SPI_OC_TINY is not set
+# CONFIG_SPI_PXA2XX_PCI is not set
+CONFIG_SPI_SPIDEV=m
+# CONFIG_SPI_TLE62X0 is not set
+# CONFIG_SPI_TOPCLIFF_PCH is not set
+# CONFIG_SPI_XILINX is not set
+CONFIG_SPLIT_PTLOCK_CPUS=999999
+CONFIG_SSB_POSSIBLE=y
+CONFIG_STACKTRACE=y
+CONFIG_STACKTRACE_SUPPORT=y
+# CONFIG_STACK_TRACER is not set
+CONFIG_STAGING=y
+CONFIG_STANDALONE=y
+# CONFIG_STE10XP is not set
+# CONFIG_STMMAC_ETH is not set
+CONFIG_STOP_MACHINE=y
+# CONFIG_STRICT_DEVMEM is not set
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_STUB_POULSBO is not set
+# CONFIG_ST_GPS is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_SUN_PARTITION is not set
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_SUSPEND_TIME is not set
+# CONFIG_SWITCH is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_SYSCTL=y
+# CONFIG_SYSCTL_SYSCALL is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_SYSFS=y
+# CONFIG_SYSFS_DEPRECATED is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_TARGET_CORE is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_TCG_ATMEL is not set
+# CONFIG_TCG_NSC is not set
+CONFIG_TCG_TPM=y
+CONFIG_TCP_CONG_ADVANCED=y
+# CONFIG_TCP_CONG_BIC is not set
+CONFIG_TCP_CONG_CUBIC=y
+# CONFIG_TCP_CONG_HSTCP is not set
+# CONFIG_TCP_CONG_HTCP is not set
+# CONFIG_TCP_CONG_HYBLA is not set
+# CONFIG_TCP_CONG_ILLINOIS is not set
+# CONFIG_TCP_CONG_LP is not set
+# CONFIG_TCP_CONG_SCALABLE is not set
+# CONFIG_TCP_CONG_VEGAS is not set
+# CONFIG_TCP_CONG_VENO is not set
+# CONFIG_TCP_CONG_WESTWOOD is not set
+# CONFIG_TCP_CONG_YEAH is not set
+CONFIG_TCP_MD5SIG=y
+# CONFIG_TEGRA_CRYPTO_DEV is not set
+# CONFIG_TEST_KSTRTOX is not set
+# CONFIG_TEST_LIST_SORT is not set
+# CONFIG_TEST_POWER is not set
+CONFIG_THERMAL=y
+CONFIG_THERMAL_HWMON=y
+CONFIG_TICK_ONESHOT=y
+# CONFIG_TIFM_CORE is not set
+CONFIG_TIMERFD=y
+CONFIG_TIMER_STATS=y
+# CONFIG_TIPC is not set
+# CONFIG_TI_DAC7512 is not set
+# CONFIG_TI_ST is not set
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_TMPFS_XATTR=y
+# CONFIG_TOUCHSCREEN_AD7877 is not set
+# CONFIG_TOUCHSCREEN_AD7879 is not set
+# CONFIG_TOUCHSCREEN_ADS7846 is not set
+# CONFIG_TOUCHSCREEN_BU21013 is not set
+# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set
+# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set
+# CONFIG_TOUCHSCREEN_DYNAPRO is not set
+# CONFIG_TOUCHSCREEN_EETI is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set
+# CONFIG_TOUCHSCREEN_INEXIO is not set
+# CONFIG_TOUCHSCREEN_MAX11801 is not set
+# CONFIG_TOUCHSCREEN_MCS5000 is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_PANJIT_I2C is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_RM31080A is not set
+# CONFIG_TOUCHSCREEN_ST1232 is not set
+# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI is not set
+# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set
+# CONFIG_TOUCHSCREEN_SYN_RMI4_SPI is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_TPS6507X is not set
+# CONFIG_TOUCHSCREEN_TSC2005 is not set
+# CONFIG_TOUCHSCREEN_TSC2007 is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TPS6105X is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TPS6507X is not set
+# CONFIG_TR is not set
+# CONFIG_TRACEDUMP is not set
+# CONFIG_TRACELEVEL is not set
+CONFIG_TRACEPOINTS=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_TRACE_SINK is not set
+CONFIG_TRACING=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_TRANZPORT is not set
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_TRUSTED_FOUNDATIONS is not set
+# CONFIG_TRUSTED_KEYS is not set
+# CONFIG_TSL2583 is not set
+# CONFIG_TTY_PRINTK is not set
+CONFIG_TUN=m
+# CONFIG_TWL4030_CORE is not set
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+CONFIG_UEVENT_HELPER_PATH=""
+# CONFIG_UFS_FS is not set
+CONFIG_UID16=y
+# CONFIG_UID_STAT is not set
+# CONFIG_UIO is not set
+# CONFIG_ULTRIX_PARTITION is not set
+CONFIG_UNIX=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_USB=y
+# CONFIG_USBIP_CORE is not set
+CONFIG_USB_ACM=y
+# CONFIG_USB_ADUTUX is not set
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+# CONFIG_USB_APPLEDISPLAY is not set
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_DEBUG is not set
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_ONOFF_FEATURE is not set
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_ENESTORAGE is not set
+# CONFIG_USB_ET61X251 is not set
+# CONFIG_USB_EZUSB is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_GADGET is not set
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_USB_GSPCA is not set
+CONFIG_USB_HID=y
+CONFIG_USB_HIDDEV=y
+# CONFIG_USB_HSO is not set
+# CONFIG_USB_HWA_HCD is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_IPHETH is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_LEGOTOWER is not set
+CONFIG_USB_LIBUSUAL=y
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_NET_CDC_EEM is not set
+# CONFIG_USB_NET_CDC_SUBSET is not set
+# CONFIG_USB_NET_CX82310_ETH is not set
+# CONFIG_USB_NET_GL620A is not set
+# CONFIG_USB_NET_INT51X1 is not set
+# CONFIG_USB_NET_KALMIA is not set
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_RAW_IP is not set
+CONFIG_USB_NET_RNDIS_HOST=m
+CONFIG_USB_NET_RNDIS_WLAN=m
+# CONFIG_USB_NET_SMSC75XX is not set
+# CONFIG_USB_NET_ZAURUS is not set
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_PWC is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_S2255 is not set
+CONFIG_USB_SERIAL=y
+# CONFIG_USB_SERIAL_AIRCABLE is not set
+# CONFIG_USB_SERIAL_ARK3116 is not set
+# CONFIG_USB_SERIAL_BASEBAND is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_CH341 is not set
+# CONFIG_USB_SERIAL_CONSOLE is not set
+# CONFIG_USB_SERIAL_CP210X is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
+# CONFIG_USB_SERIAL_DEBUG is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_FUNSOFT is not set
+# CONFIG_USB_SERIAL_GARMIN is not set
+CONFIG_USB_SERIAL_GENERIC=y
+# CONFIG_USB_SERIAL_HP4X is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IPW is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_IUU is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_MOS7720 is not set
+# CONFIG_USB_SERIAL_MOS7840 is not set
+# CONFIG_USB_SERIAL_MOTOROLA is not set
+# CONFIG_USB_SERIAL_NAVMAN is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_SERIAL_OPTICON is not set
+CONFIG_USB_SERIAL_OPTION=m
+# CONFIG_USB_SERIAL_OTI6858 is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_QCAUX is not set
+CONFIG_USB_SERIAL_QUALCOMM=m
+# CONFIG_USB_SERIAL_QUATECH2 is not set
+# CONFIG_USB_SERIAL_QUATECH_USB2 is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_SIEMENS_MPI is not set
+# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
+# CONFIG_USB_SERIAL_SPCP8X5 is not set
+# CONFIG_USB_SERIAL_SSU100 is not set
+# CONFIG_USB_SERIAL_SYMBOL is not set
+# CONFIG_USB_SERIAL_TI is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_VIVOPAY_SERIAL is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+CONFIG_USB_SERIAL_WWAN=m
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_ZIO is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_SIERRA_NET is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_SN9C102 is not set
+# CONFIG_USB_STKWEBCAM is not set
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_ENE_UB6250 is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_SUSPEND=y
+# CONFIG_USB_SWITCH_FSA9480 is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_TMC is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_UAS is not set
+CONFIG_USB_VIDEO_CLASS=m
+# CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV is not set
+# CONFIG_USB_VL600 is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_WHCI_HCD is not set
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+# CONFIG_USB_XHCI_HCD is not set
+# CONFIG_USB_YUREX is not set
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_USB_ZR364XX is not set
+CONFIG_USER_NS=y
+CONFIG_USE_GENERIC_SMP_HELPERS=y
+CONFIG_UTS_NS=y
+# CONFIG_UWB is not set
+# CONFIG_V4L_MEM2MEM_DRIVERS is not set
+CONFIG_V4L_USB_DRIVERS=y
+CONFIG_VETH=m
+CONFIG_VFAT_FS=m
+# CONFIG_VGASTATE is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_VIDEO_ADV7170 is not set
+# CONFIG_VIDEO_ADV7175 is not set
+# CONFIG_VIDEO_ADV7180 is not set
+# CONFIG_VIDEO_ADV7343 is not set
+# CONFIG_VIDEO_ADV_DEBUG is not set
+# CONFIG_VIDEO_AK881X is not set
+# CONFIG_VIDEO_BT819 is not set
+# CONFIG_VIDEO_BT856 is not set
+# CONFIG_VIDEO_BT866 is not set
+# CONFIG_VIDEO_CAFE_CCIC is not set
+CONFIG_VIDEO_CAPTURE_DRIVERS=y
+# CONFIG_VIDEO_CPIA2 is not set
+# CONFIG_VIDEO_CS5345 is not set
+# CONFIG_VIDEO_CS53L32A is not set
+# CONFIG_VIDEO_CX2341X is not set
+# CONFIG_VIDEO_CX25840 is not set
+CONFIG_VIDEO_DEV=m
+# CONFIG_VIDEO_DT3155 is not set
+# CONFIG_VIDEO_EM28XX is not set
+# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
+# CONFIG_VIDEO_HDPVR is not set
+# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set
+# CONFIG_VIDEO_HEXIUM_GEMINI is not set
+# CONFIG_VIDEO_HEXIUM_ORION is not set
+# CONFIG_VIDEO_KS0127 is not set
+# CONFIG_VIDEO_M52790 is not set
+CONFIG_VIDEO_MEDIA=m
+# CONFIG_VIDEO_MSP3400 is not set
+# CONFIG_VIDEO_MT9V011 is not set
+# CONFIG_VIDEO_MXB is not set
+# CONFIG_VIDEO_NOON010PC30 is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=y
+# CONFIG_VIDEO_OV7670 is not set
+# CONFIG_VIDEO_PVRUSB2 is not set
+# CONFIG_VIDEO_SAA6588 is not set
+# CONFIG_VIDEO_SAA7110 is not set
+# CONFIG_VIDEO_SAA711X is not set
+# CONFIG_VIDEO_SAA7127 is not set
+# CONFIG_VIDEO_SAA7134 is not set
+# CONFIG_VIDEO_SAA717X is not set
+# CONFIG_VIDEO_SAA7185 is not set
+# CONFIG_VIDEO_SAA7191 is not set
+# CONFIG_VIDEO_SR030PC30 is not set
+# CONFIG_VIDEO_TCM825X is not set
+# CONFIG_VIDEO_TDA7432 is not set
+# CONFIG_VIDEO_TDA9840 is not set
+# CONFIG_VIDEO_TEA6415C is not set
+# CONFIG_VIDEO_TEA6420 is not set
+# CONFIG_VIDEO_THS7303 is not set
+# CONFIG_VIDEO_TLV320AIC23B is not set
+# CONFIG_VIDEO_TVAUDIO is not set
+# CONFIG_VIDEO_TVP514X is not set
+# CONFIG_VIDEO_TVP5150 is not set
+# CONFIG_VIDEO_TVP7002 is not set
+# CONFIG_VIDEO_UPD64031A is not set
+# CONFIG_VIDEO_UPD64083 is not set
+# CONFIG_VIDEO_USBVISION is not set
+CONFIG_VIDEO_V4L2=m
+CONFIG_VIDEO_V4L2_COMMON=m
+# CONFIG_VIDEO_VP27SMPX is not set
+# CONFIG_VIDEO_VPX3220 is not set
+# CONFIG_VIDEO_WM8739 is not set
+# CONFIG_VIDEO_WM8775 is not set
+# CONFIG_VIRTIO_BALLOON is not set
+# CONFIG_VIRT_DRIVERS is not set
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_VME_BUS is not set
+# CONFIG_VMXNET3 is not set
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_VT=y
+# CONFIG_VT6655 is not set
+# CONFIG_VT6656 is not set
+CONFIG_VT_CONSOLE=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_W1 is not set
+# CONFIG_W35UND is not set
+# CONFIG_WAKELOCK is not set
+# CONFIG_WAN is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_WEXT_CORE=y
+CONFIG_WEXT_PRIV=y
+CONFIG_WEXT_PROC=y
+CONFIG_WEXT_SPY=y
+# CONFIG_WIFI_CONTROL_FUNC is not set
+# CONFIG_WIMAX is not set
+CONFIG_WIRELESS=y
+CONFIG_WIRELESS_EXT=y
+# CONFIG_WIRELESS_EXT_SYSFS is not set
+# CONFIG_WL1251 is not set
+# CONFIG_WL127X_RFKILL is not set
+# CONFIG_WL12XX_MENU is not set
+CONFIG_WLAN=y
+# CONFIG_X25 is not set
+CONFIG_XFRM=y
+CONFIG_XFRM_IPCOMP=m
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFS_FS is not set
+CONFIG_XPS=y
+# CONFIG_XVMALLOC is not set
+# CONFIG_XZ_DEC is not set
+# CONFIG_XZ_DEC_BCJ is not set
+# CONFIG_YELLOWFIN is not set
+CONFIG_ZISOFS=y
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_ZLIB_INFLATE=y
+# CONFIG_ZRAM is not set
diff --git a/chromeos/config/i386/config.common.i386 b/chromeos/config/i386/config.common.i386
new file mode 100644
index 000000000000..a5a85733af59
--- /dev/null
+++ b/chromeos/config/i386/config.common.i386
@@ -0,0 +1,752 @@
+#
+# Config options generated by splitconfig
+#
+# CONFIG_64BIT is not set
+# CONFIG_ACERHDF is not set
+# CONFIG_ACER_WMI is not set
+CONFIG_ACPI=y
+CONFIG_ACPI_AC=y
+# CONFIG_ACPI_APEI is not set
+# CONFIG_ACPI_ASUS is not set
+CONFIG_ACPI_BATTERY=y
+CONFIG_ACPI_BLACKLIST_YEAR=0
+CONFIG_ACPI_BUTTON=y
+# CONFIG_ACPI_CMPC is not set
+CONFIG_ACPI_CONTAINER=y
+# CONFIG_ACPI_CUSTOM_DSDT is not set
+# CONFIG_ACPI_CUSTOM_METHOD is not set
+# CONFIG_ACPI_DEBUG is not set
+CONFIG_ACPI_DOCK=y
+# CONFIG_ACPI_EC_DEBUGFS is not set
+CONFIG_ACPI_FAN=y
+# CONFIG_ACPI_HED is not set
+CONFIG_ACPI_HOTPLUG_CPU=y
+# CONFIG_ACPI_PCI_SLOT is not set
+CONFIG_ACPI_PROCESSOR=y
+# CONFIG_ACPI_PROCESSOR_AGGREGATOR is not set
+CONFIG_ACPI_PROCFS=y
+CONFIG_ACPI_PROCFS_POWER=y
+CONFIG_ACPI_PROC_EVENT=y
+# CONFIG_ACPI_QUICKSTART is not set
+# CONFIG_ACPI_SBS is not set
+CONFIG_ACPI_SLEEP=y
+CONFIG_ACPI_THERMAL=y
+# CONFIG_ACPI_TOSHIBA is not set
+CONFIG_ACPI_VIDEO=y
+# CONFIG_ADAPTEC_STARFIRE is not set
+CONFIG_AGP=y
+# CONFIG_AGP_ALI is not set
+# CONFIG_AGP_AMD is not set
+# CONFIG_AGP_AMD64 is not set
+# CONFIG_AGP_ATI is not set
+# CONFIG_AGP_EFFICEON is not set
+CONFIG_AGP_INTEL=y
+# CONFIG_AGP_NVIDIA is not set
+# CONFIG_AGP_SIS is not set
+# CONFIG_AGP_SWORKS is not set
+# CONFIG_AGP_VIA is not set
+# CONFIG_AIRO is not set
+CONFIG_AMD_NB=y
+CONFIG_ANDROID_PARANOID_NETWORK=y
+# CONFIG_APM is not set
+CONFIG_ARCH_CPU_PROBE_RELEASE=y
+CONFIG_ARCH_DEFCONFIG="arch/x86/configs/i386_defconfig"
+# CONFIG_ARCH_DMA_ADDR_T_64BIT is not set
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y
+CONFIG_ARCH_HAS_CPU_RELAX=y
+CONFIG_ARCH_HAS_DEFAULT_IDLE=y
+CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_HWEIGHT_CFLAGS="-fcall-saved-ecx -fcall-saved-edx"
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
+CONFIG_ARCH_SUPPORTS_MSI=y
+CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y
+CONFIG_ARCH_USES_PG_UNCACHED=y
+CONFIG_ARCH_WANT_FRAME_POINTERS=y
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+# CONFIG_ASUS_LAPTOP is not set
+# CONFIG_ASUS_WMI is not set
+CONFIG_ATA=y
+CONFIG_ATA_ACPI=y
+CONFIG_ATA_BMDMA=y
+CONFIG_ATA_GENERIC=y
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_ATA_PIIX=y
+CONFIG_ATA_SFF=y
+CONFIG_ATA_VERBOSE_ERROR=y
+CONFIG_ATH5K=m
+# CONFIG_ATH5K_DEBUG is not set
+CONFIG_ATH5K_PCI=y
+# CONFIG_ATH5K_TRACER is not set
+CONFIG_ATH9K=m
+# CONFIG_ATH9K_AHB is not set
+CONFIG_ATH9K_COMMON=m
+CONFIG_ATH9K_DEBUGFS=y
+CONFIG_ATH9K_HW=m
+CONFIG_ATH9K_PCI=y
+CONFIG_ATH9K_RATE_CONTROL=y
+# CONFIG_AUDIT_ARCH is not set
+# CONFIG_BACKLIGHT_APPLE is not set
+# CONFIG_BACKLIGHT_PROGEAR is not set
+# CONFIG_BACKLIGHT_SAHARA is not set
+# CONFIG_BATTERY_BQ20Z75 is not set
+# CONFIG_BATTERY_BQ27x00 is not set
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_BT_ATH3K=m
+CONFIG_BT_HCIBCM203X=m
+CONFIG_BT_HCIBPA10X=m
+# CONFIG_BT_HCIUART is not set
+# CONFIG_CHARGER_GPIO is not set
+CONFIG_CHECK_SIGNATURE=y
+CONFIG_CLKBLD_I8253=y
+CONFIG_CLKEVT_I8253=y
+CONFIG_CLKSRC_I8253=y
+CONFIG_CLOCKSOURCE_WATCHDOG=y
+# CONFIG_CMDLINE_BOOL is not set
+CONFIG_CMPXCHG_DOUBLE=y
+CONFIG_CMPXCHG_LOCAL=y
+# CONFIG_COMEDI is not set
+# CONFIG_COMPAL_LAPTOP is not set
+# CONFIG_COMPAT_BRK is not set
+# CONFIG_COMPAT_VDSO is not set
+CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
+# CONFIG_CPA_DEBUG is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_GOV_USERSPACE is not set
+CONFIG_CPU_SUP_AMD=y
+CONFIG_CPU_SUP_CENTAUR=y
+CONFIG_CPU_SUP_CYRIX_32=y
+CONFIG_CPU_SUP_INTEL=y
+CONFIG_CPU_SUP_TRANSMETA_32=y
+CONFIG_CPU_SUP_UMC_32=y
+CONFIG_CRYPTO_AES_586=y
+CONFIG_CRYPTO_AES_NI_INTEL=m
+# CONFIG_CRYPTO_CRC32C_INTEL is not set
+CONFIG_CRYPTO_CRYPTD=m
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_DEV_GEODE is not set
+# CONFIG_CRYPTO_DEV_PADLOCK is not set
+# CONFIG_CRYPTO_SALSA20_586 is not set
+# CONFIG_CRYPTO_TWOFISH_586 is not set
+# CONFIG_DCDBAS is not set
+CONFIG_DEBUG_BOOT_PARAMS=y
+# CONFIG_DEBUG_NX_TEST is not set
+CONFIG_DEBUG_RODATA=y
+# CONFIG_DEBUG_RODATA_TEST is not set
+# CONFIG_DEBUG_SET_MODULE_RONX is not set
+CONFIG_DEBUG_STACKOVERFLOW=y
+# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set
+# CONFIG_DEBUG_VIRTUAL is not set
+CONFIG_DEFAULT_IO_DELAY_TYPE=0
+# CONFIG_DELL_RBU is not set
+CONFIG_DELL_WMI=m
+# CONFIG_DELL_WMI_AIO is not set
+CONFIG_DMI=y
+CONFIG_DMIID=y
+# CONFIG_DMI_SYSFS is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_DNS_RESOLVER is not set
+CONFIG_DOUBLEFAULT=y
+CONFIG_DRM=y
+# CONFIG_DRM_I2C_CH7006 is not set
+# CONFIG_DRM_I2C_SIL164 is not set
+# CONFIG_DRM_I810 is not set
+CONFIG_DRM_I915=y
+CONFIG_DRM_I915_KMS=y
+CONFIG_DRM_KMS_HELPER=y
+# CONFIG_DRM_MGA is not set
+# CONFIG_DRM_PSB is not set
+# CONFIG_DRM_R128 is not set
+# CONFIG_DRM_SAVAGE is not set
+# CONFIG_DRM_SIS is not set
+# CONFIG_DRM_TDFX is not set
+# CONFIG_DRM_VIA is not set
+# CONFIG_DRM_VMWGFX is not set
+CONFIG_E100=m
+CONFIG_E1000=m
+CONFIG_E1000E=m
+CONFIG_EARLY_PRINTK_DBGP=y
+# CONFIG_EDAC is not set
+# CONFIG_EDD is not set
+# CONFIG_EEEPC_LAPTOP is not set
+CONFIG_EFI=y
+# CONFIG_EFI_VARS is not set
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_FB_ARC is not set
+# CONFIG_FB_EFI is not set
+# CONFIG_FB_GEODE is not set
+# CONFIG_FB_HGA is not set
+# CONFIG_FB_I810 is not set
+# CONFIG_FB_LE80578 is not set
+# CONFIG_FB_N411 is not set
+# CONFIG_FB_VESA is not set
+# CONFIG_FB_VGA16 is not set
+# CONFIG_FB_VIA is not set
+# CONFIG_FEALNX is not set
+CONFIG_FIRMWARE_MEMMAP=y
+CONFIG_FIX_EARLYCON_MEM=y
+# CONFIG_FLATMEM_MANUAL is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x16=y
+CONFIG_FONT_8x8=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FRAME_WARN=2048
+CONFIG_FTRACE_NMI_ENTER=y
+CONFIG_FTRACE_SYSCALLS=y
+# CONFIG_FUJITSU_LAPTOP is not set
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_FIND_FIRST_BIT=y
+CONFIG_GENERIC_IOMAP=y
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_GENERIC_PENDING_IRQ=y
+# CONFIG_GENERIC_TIME_VSYSCALL is not set
+# CONFIG_GOOGLE_FIRMWARE is not set
+# CONFIG_GPIO_LANGWELL is not set
+# CONFIG_GPIO_PCH is not set
+# CONFIG_GPIO_SCH is not set
+# CONFIG_HANGCHECK_TIMER is not set
+CONFIG_HARDLOCKUP_DETECTOR=y
+CONFIG_HAVE_AOUT=y
+CONFIG_HAVE_ARCH_JUMP_LABEL=y
+CONFIG_HAVE_ARCH_KMEMCHECK=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_ATOMIC_IOMAP=y
+# CONFIG_HAVE_CPUMASK_OF_CPU_MAP is not set
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_HAVE_FTRACE_NMI_ENTER=y
+CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST=y
+CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_HAVE_IOREMAP_PROT=y
+CONFIG_HAVE_KERNEL_BZIP2=y
+CONFIG_HAVE_KERNEL_XZ=y
+CONFIG_HAVE_KVM=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_HAVE_MEMORY_PRESENT=y
+CONFIG_HAVE_MIXED_BREAKPOINTS_REGS=y
+CONFIG_HAVE_MMIOTRACE_SUPPORT=y
+CONFIG_HAVE_OPTPROBES=y
+CONFIG_HAVE_PCSPKR_PLATFORM=y
+CONFIG_HAVE_PERF_EVENTS_NMI=y
+CONFIG_HAVE_SETUP_PER_CPU_AREA=y
+CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
+CONFIG_HAVE_TEXT_POKE_SMP=y
+CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y
+CONFIG_HAVE_USER_RETURN_NOTIFIER=y
+CONFIG_HID_MICROSOFT=m
+CONFIG_HID_PID=y
+# CONFIG_HIGHMEM4G is not set
+# CONFIG_HIGHMEM64G is not set
+CONFIG_HOSTAP_PCI=m
+CONFIG_HOSTAP_PLX=m
+CONFIG_HOTPLUG_PCI=y
+# CONFIG_HOTPLUG_PCI_ACPI is not set
+# CONFIG_HOTPLUG_PCI_COMPAQ is not set
+# CONFIG_HOTPLUG_PCI_CPCI is not set
+# CONFIG_HOTPLUG_PCI_FAKE is not set
+# CONFIG_HOTPLUG_PCI_IBM is not set
+CONFIG_HOTPLUG_PCI_PCIE=y
+# CONFIG_HOTPLUG_PCI_SHPC is not set
+CONFIG_HPET=y
+CONFIG_HPET_EMULATE_RTC=y
+# CONFIG_HPET_MMAP is not set
+CONFIG_HPET_TIMER=y
+# CONFIG_HP_ACCEL is not set
+CONFIG_HP_WMI=m
+CONFIG_HT_IRQ=y
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HW_RANDOM_AMD is not set
+# CONFIG_HW_RANDOM_GEODE is not set
+CONFIG_HW_RANDOM_INTEL=y
+# CONFIG_HW_RANDOM_VIA is not set
+# CONFIG_HW_RANDOM_VIRTIO is not set
+# CONFIG_HYPERV is not set
+CONFIG_HZ=1000
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_1000=y
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
+CONFIG_I2C_ALGOBIT=y
+CONFIG_I2C_I801=m
+CONFIG_I2C_PIIX4=m
+# CONFIG_I2C_SCMI is not set
+# CONFIG_I8K is not set
+# CONFIG_IBM_ASM is not set
+# CONFIG_IBM_RTL is not set
+# CONFIG_IDEAPAD_LAPTOP is not set
+# CONFIG_IDE_PHISON is not set
+CONFIG_IGBVF=m
+CONFIG_ILLEGAL_POINTER_VALUE=0
+# CONFIG_INPUT_APANEL is not set
+# CONFIG_INPUT_ATLAS_BTNS is not set
+CONFIG_INPUT_SPARSEKMAP=m
+# CONFIG_INPUT_WISTRON_BTNS is not set
+CONFIG_INSTRUCTION_DECODER=y
+# CONFIG_INTEL_IDLE is not set
+# CONFIG_INTEL_IOMMU is not set
+# CONFIG_INTEL_IPS is not set
+# CONFIG_INTEL_MEI is not set
+CONFIG_INTEL_MENLOW=m
+# CONFIG_INTEL_OAKTRAIL is not set
+# CONFIG_IOMMU_HELPER is not set
+# CONFIG_IOMMU_STRESS is not set
+CONFIG_IO_DELAY_0X80=y
+# CONFIG_IO_DELAY_0XED is not set
+# CONFIG_IO_DELAY_NONE is not set
+CONFIG_IO_DELAY_TYPE_0X80=0
+CONFIG_IO_DELAY_TYPE_0XED=1
+CONFIG_IO_DELAY_TYPE_NONE=3
+CONFIG_IO_DELAY_TYPE_UDELAY=2
+# CONFIG_IO_DELAY_UDELAY is not set
+CONFIG_IPV6=m
+# CONFIG_IP_PNP is not set
+CONFIG_IRQ_FORCED_THREADING=y
+# CONFIG_IRQ_TIME_ACCOUNTING is not set
+# CONFIG_IR_ENE is not set
+# CONFIG_IR_FINTEK is not set
+# CONFIG_IR_IMON is not set
+# CONFIG_IR_ITE_CIR is not set
+# CONFIG_IR_JVC_DECODER is not set
+# CONFIG_IR_LIRC_CODEC is not set
+# CONFIG_IR_MCEUSB is not set
+CONFIG_IR_MCE_KBD_DECODER=m
+# CONFIG_IR_NEC_DECODER is not set
+# CONFIG_IR_NUVOTON is not set
+# CONFIG_IR_RC5_DECODER is not set
+# CONFIG_IR_RC5_SZ_DECODER is not set
+# CONFIG_IR_RC6_DECODER is not set
+# CONFIG_IR_REDRAT3 is not set
+# CONFIG_IR_SONY_DECODER is not set
+# CONFIG_IR_STREAMZAP is not set
+# CONFIG_IR_WINBOND_CIR is not set
+# CONFIG_ISA is not set
+CONFIG_ISA_DMA_API=y
+# CONFIG_ISCSI_IBFT_FIND is not set
+CONFIG_JME=m
+# CONFIG_JUMP_LABEL is not set
+# CONFIG_KERNEL_BZIP2 is not set
+# CONFIG_KERNEL_XZ is not set
+# CONFIG_KSZ884X_PCI is not set
+CONFIG_KTIME_SCALAR=y
+# CONFIG_KVM is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_LBDAF=y
+# CONFIG_LEDS_ALIX2 is not set
+# CONFIG_LEDS_CLEVO_MAIL is not set
+# CONFIG_LEDS_DELL_NETBOOKS is not set
+# CONFIG_LEDS_INTEL_SS4200 is not set
+# CONFIG_LGUEST is not set
+CONFIG_LIBERTAS_THINFIRM_USB=m
+CONFIG_LIRC=m
+# CONFIG_LIRC_STAGING is not set
+CONFIG_LPC_SCH=m
+# CONFIG_M386 is not set
+# CONFIG_M486 is not set
+# CONFIG_M586 is not set
+# CONFIG_M586MMX is not set
+# CONFIG_M586TSC is not set
+CONFIG_M686=y
+# CONFIG_MAC80211_MESH is not set
+# CONFIG_MACINTOSH_DRIVERS is not set
+# CONFIG_MATH_EMULATION is not set
+# CONFIG_MATOM is not set
+# CONFIG_MCA is not set
+# CONFIG_MCORE2 is not set
+# CONFIG_MCRUSOE is not set
+# CONFIG_MCYRIXIII is not set
+# CONFIG_MEFFICEON is not set
+# CONFIG_MELAN is not set
+# CONFIG_MEMTEST is not set
+CONFIG_MFD_CORE=m
+# CONFIG_MFD_CS5535 is not set
+# CONFIG_MFD_TPS6586X is not set
+# CONFIG_MFD_TPS6591X is not set
+# CONFIG_MGEODEGX1 is not set
+# CONFIG_MGEODE_LX is not set
+CONFIG_MICROCODE=y
+CONFIG_MICROCODE_AMD=y
+CONFIG_MICROCODE_INTEL=y
+CONFIG_MICROCODE_OLD_INTERFACE=y
+# CONFIG_MK6 is not set
+# CONFIG_MK7 is not set
+# CONFIG_MK8 is not set
+# CONFIG_MMC is not set
+# CONFIG_MMIOTRACE is not set
+CONFIG_MOUSE_APPLETOUCH=m
+CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_ELANTECH=y
+CONFIG_MOUSE_PS2_LIFEBOOK=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+# CONFIG_MOUSE_PS2_SENTELIC is not set
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MPENTIUM4 is not set
+# CONFIG_MPENTIUMII is not set
+# CONFIG_MPENTIUMIII is not set
+# CONFIG_MPENTIUMM is not set
+# CONFIG_MSI_LAPTOP is not set
+# CONFIG_MSI_WMI is not set
+CONFIG_MTRR=y
+# CONFIG_MTRR_SANITIZER is not set
+# CONFIG_MVIAC3_2 is not set
+# CONFIG_MVIAC7 is not set
+# CONFIG_MWAVE is not set
+# CONFIG_MWINCHIP3D is not set
+# CONFIG_MWINCHIPC6 is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_NEED_DMA_MAP_STATE is not set
+CONFIG_NEED_NODE_MEMMAP_SIZE=y
+CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y
+CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
+CONFIG_NEED_SG_DMA_LENGTH=y
+# CONFIG_NETWORK_FILESYSTEMS is not set
+CONFIG_NET_PCI=y
+# CONFIG_NET_SB1000 is not set
+CONFIG_NOHIGHMEM=y
+CONFIG_NO_BOOTMEM=y
+CONFIG_NR_CPUS=4
+# CONFIG_NSC_GPIO is not set
+CONFIG_NVRAM=y
+CONFIG_OPTIMIZE_INLINING=y
+CONFIG_OUTPUT_FORMAT="elf32-i386"
+CONFIG_PAGE_OFFSET=0x80000000
+# CONFIG_PANASONIC_LAPTOP is not set
+# CONFIG_PARAVIRT_GUEST is not set
+# CONFIG_PATA_ACPI is not set
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_ATP867X is not set
+# CONFIG_PATA_CMD640_PCI is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CS5535 is not set
+# CONFIG_PATA_CS5536 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_LEGACY is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NINJA32 is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_NS87415 is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_PLATFORM is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RDC is not set
+# CONFIG_PATA_RZ1000 is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SCH is not set
+# CONFIG_PATA_SERVERWORKS is not set
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_TOSHIBA is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+# CONFIG_PC8736x_GPIO is not set
+CONFIG_PCIEAER=y
+# CONFIG_PCIEAER_INJECT is not set
+CONFIG_PCIEASPM=y
+# CONFIG_PCIEASPM_DEBUG is not set
+CONFIG_PCIEASPM_DEFAULT=y
+# CONFIG_PCIEASPM_PERFORMANCE is not set
+# CONFIG_PCIEASPM_POWERSAVE is not set
+CONFIG_PCIEPORTBUS=y
+# CONFIG_PCIE_ECRC is not set
+CONFIG_PCIE_PME=y
+CONFIG_PCI_BIOS=y
+# CONFIG_PCI_CNB20LE_QUIRK is not set
+CONFIG_PCI_DIRECT=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_GOANY=y
+# CONFIG_PCI_GOBIOS is not set
+# CONFIG_PCI_GODIRECT is not set
+# CONFIG_PCI_GOMMCONFIG is not set
+CONFIG_PCI_IOAPIC=y
+CONFIG_PCI_LABEL=y
+CONFIG_PCI_MMCONFIG=y
+CONFIG_PCI_MSI=y
+# CONFIG_PCSPKR_PLATFORM is not set
+# CONFIG_PDC_ADMA is not set
+CONFIG_PHYSICAL_ALIGN=0x200000
+CONFIG_PHYSICAL_START=0x1000000
+CONFIG_PHYS_ADDR_T_64BIT=y
+CONFIG_PM_TRACE=y
+CONFIG_PM_TRACE_RTC=y
+CONFIG_PNP=y
+CONFIG_PNPACPI=y
+CONFIG_PNP_DEBUG_MESSAGES=y
+# CONFIG_PROCESSOR_SELECT is not set
+CONFIG_PROC_KCORE=y
+CONFIG_PROVIDE_OHCI1394_DMA_INIT=y
+# CONFIG_R6040 is not set
+# CONFIG_RAPIDIO is not set
+CONFIG_RC_CORE=m
+# CONFIG_RC_LOOPBACK is not set
+CONFIG_RC_MAP=m
+CONFIG_REALTEK_AUTOPM=y
+# CONFIG_REGULATOR is not set
+# CONFIG_RELOCATABLE is not set
+# CONFIG_REPORT_PRESENT_CPUS is not set
+CONFIG_RTC_DRV_CMOS=m
+# CONFIG_RTC_HCTOSYS is not set
+# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+# CONFIG_SAMSUNG_LAPTOP is not set
+# CONFIG_SAMSUNG_Q10 is not set
+# CONFIG_SATA_ACARD_AHCI is not set
+CONFIG_SATA_AHCI=y
+# CONFIG_SATA_AHCI_PLATFORM is not set
+# CONFIG_SATA_INIC162X is not set
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
+# CONFIG_SATA_PMP is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_SIL is not set
+# CONFIG_SATA_SIL24 is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_SVW is not set
+# CONFIG_SATA_SX4 is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
+# CONFIG_SC92031 is not set
+CONFIG_SCHED_HRTICK=y
+CONFIG_SCHED_MC=y
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+CONFIG_SCHED_SMT=y
+CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOWLEVEL is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+# CONFIG_SCx200 is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ABITUGURU3 is not set
+# CONFIG_SENSORS_ACPI_POWER is not set
+# CONFIG_SENSORS_APPLESMC is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATK0110 is not set
+CONFIG_SENSORS_CORETEMP=y
+# CONFIG_SENSORS_FAM15H_POWER is not set
+# CONFIG_SENSORS_FSCHMD is not set
+# CONFIG_SENSORS_HDAPS is not set
+# CONFIG_SENSORS_ISL29018 is not set
+# CONFIG_SENSORS_ISL29028 is not set
+# CONFIG_SENSORS_K10TEMP is not set
+# CONFIG_SENSORS_K8TEMP is not set
+# CONFIG_SENSORS_NCT1008 is not set
+# CONFIG_SENSORS_VIA_CPUTEMP is not set
+# CONFIG_SERIAL_8250 is not set
+CONFIG_SERIO_CT82C710=m
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_PCIPS2=m
+# CONFIG_SFI is not set
+# CONFIG_SIGMA is not set
+# CONFIG_SIS900 is not set
+# CONFIG_SLAB is not set
+# CONFIG_SLICOSS is not set
+CONFIG_SLUB=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+# CONFIG_SMSC9420 is not set
+# CONFIG_SND_ALS4000 is not set
+# CONFIG_SND_ASIHPI is not set
+# CONFIG_SND_CS5530 is not set
+CONFIG_SND_DMA_SGBUF=y
+CONFIG_SND_HDA_CODEC_ANALOG=y
+CONFIG_SND_HDA_CODEC_CA0110=y
+CONFIG_SND_HDA_CODEC_CA0132=y
+CONFIG_SND_HDA_CODEC_CIRRUS=y
+CONFIG_SND_HDA_CODEC_CMEDIA=y
+CONFIG_SND_HDA_CODEC_CONEXANT=y
+CONFIG_SND_HDA_CODEC_HDMI=y
+CONFIG_SND_HDA_CODEC_REALTEK=y
+CONFIG_SND_HDA_CODEC_SI3054=y
+CONFIG_SND_HDA_CODEC_SIGMATEL=y
+CONFIG_SND_HDA_CODEC_VIA=y
+CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS=y
+CONFIG_SND_HDA_GENERIC=y
+CONFIG_SND_HDA_HWDEP=y
+# CONFIG_SND_HDA_INPUT_BEEP is not set
+CONFIG_SND_HDA_INPUT_JACK=y
+CONFIG_SND_HDA_INTEL=m
+# CONFIG_SND_HDA_PATCH_LOADER is not set
+# CONFIG_SND_HDA_PLATFORM_DRIVER is not set
+CONFIG_SND_HDA_POWER_SAVE=y
+CONFIG_SND_HDA_POWER_SAVE_DEFAULT=5
+CONFIG_SND_HDA_PREALLOC_SIZE=64
+# CONFIG_SND_HDA_RECONFIG is not set
+CONFIG_SND_PCM=m
+# CONFIG_SND_SIS7019 is not set
+# CONFIG_SND_SOC is not set
+CONFIG_SND_TIMER=m
+# CONFIG_SND_USB_US122L is not set
+# CONFIG_SND_USB_USX2Y is not set
+CONFIG_SND_VMASTER=y
+# CONFIG_SOC_CAMERA is not set
+# CONFIG_SONYPI is not set
+# CONFIG_SONY_LAPTOP is not set
+CONFIG_SPARSEMEM=y
+CONFIG_SPARSEMEM_MANUAL=y
+CONFIG_SPARSEMEM_STATIC=y
+CONFIG_SPARSE_IRQ=y
+# CONFIG_SPI_PXA2XX is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_SWAP is not set
+# CONFIG_TC1100_WMI is not set
+# CONFIG_TCG_INFINEON is not set
+CONFIG_TCG_TIS=y
+# CONFIG_TELCLOCK is not set
+# CONFIG_THINKPAD_ACPI is not set
+# CONFIG_TLAN is not set
+# CONFIG_TOPSTAR_LAPTOP is not set
+# CONFIG_TOSHIBA is not set
+# CONFIG_TOSHIBA_BT_RFKILL is not set
+# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set
+# CONFIG_TRANSPARENT_HUGEPAGE is not set
+CONFIG_USB_NET_AX8817X=m
+CONFIG_USB_NET_CDCETHER=m
+CONFIG_USB_NET_CDC_NCM=m
+CONFIG_USB_NET_DM9601=m
+CONFIG_USB_NET_MCS7830=m
+CONFIG_USB_NET_NET1080=m
+CONFIG_USB_NET_SMSC95XX=m
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+CONFIG_USB_STORAGE_REALTEK=y
+CONFIG_USB_UHCI_HCD=y
+CONFIG_USB_USBNET=m
+CONFIG_USER_STACKTRACE_SUPPORT=y
+# CONFIG_VGACON_SOFT_SCROLLBACK is not set
+# CONFIG_VGA_ARB is not set
+CONFIG_VGA_CONSOLE=y
+# CONFIG_VGA_SWITCHEROO is not set
+# CONFIG_VHOST_NET is not set
+# CONFIG_VIDEO_BT848 is not set
+# CONFIG_VIDEO_CX231XX is not set
+# CONFIG_VIDEO_CX88 is not set
+# CONFIG_VIDEO_GO7007 is not set
+# CONFIG_VIDEO_IR_I2C is not set
+# CONFIG_VIDEO_IVTV is not set
+# CONFIG_VIDEO_TM6000 is not set
+# CONFIG_VIDEO_VIVI is not set
+# CONFIG_VIDEO_ZORAN is not set
+CONFIG_VIRTIO=m
+CONFIG_VIRTIO_BLK=m
+# CONFIG_VIRTIO_CONSOLE is not set
+CONFIG_VIRTIO_NET=m
+CONFIG_VIRTIO_PCI=m
+CONFIG_VIRTIO_RING=m
+CONFIG_VIRTUALIZATION=y
+# CONFIG_VM86 is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_VMSPLIT_2G=y
+# CONFIG_VMSPLIT_3G is not set
+# CONFIG_VMWARE_BALLOON is not set
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_X86=y
+CONFIG_X86_32=y
+# CONFIG_X86_32_IRIS is not set
+# CONFIG_X86_32_NON_STANDARD is not set
+CONFIG_X86_32_SMP=y
+# CONFIG_X86_64 is not set
+CONFIG_X86_ACPI_CPUFREQ=y
+# CONFIG_X86_ANCIENT_MCE is not set
+# CONFIG_X86_BIGSMP is not set
+CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK=y
+CONFIG_X86_BSWAP=y
+CONFIG_X86_CHECK_BIOS_CORRUPTION=y
+CONFIG_X86_CMOV=y
+CONFIG_X86_CMPXCHG=y
+CONFIG_X86_CMPXCHG64=y
+# CONFIG_X86_CPUFREQ_NFORCE2 is not set
+CONFIG_X86_CPUID=y
+CONFIG_X86_DEBUGCTLMSR=y
+CONFIG_X86_EXTENDED_PLATFORM=y
+# CONFIG_X86_E_POWERSAVER is not set
+# CONFIG_X86_GENERIC is not set
+# CONFIG_X86_GX_SUSPMOD is not set
+CONFIG_X86_HT=y
+# CONFIG_X86_INTEL_MID is not set
+CONFIG_X86_INTERNODE_CACHE_SHIFT=5
+CONFIG_X86_INVLPG=y
+CONFIG_X86_IO_APIC=y
+CONFIG_X86_L1_CACHE_SHIFT=5
+CONFIG_X86_LOCAL_APIC=y
+# CONFIG_X86_LONGHAUL is not set
+# CONFIG_X86_LONGRUN is not set
+CONFIG_X86_MCE=y
+# CONFIG_X86_MCE_AMD is not set
+# CONFIG_X86_MCE_INJECT is not set
+CONFIG_X86_MCE_INTEL=y
+CONFIG_X86_MCE_THRESHOLD=y
+CONFIG_X86_MINIMUM_CPU_FAMILY=5
+CONFIG_X86_MPPARSE=y
+CONFIG_X86_MSR=y
+# CONFIG_X86_P4_CLOCKMOD is not set
+CONFIG_X86_PAE=y
+CONFIG_X86_PAT=y
+# CONFIG_X86_PCC_CPUFREQ is not set
+CONFIG_X86_PLATFORM_DEVICES=y
+CONFIG_X86_PM_TIMER=y
+CONFIG_X86_POPAD_OK=y
+# CONFIG_X86_PPRO_FENCE is not set
+# CONFIG_X86_PTDUMP is not set
+# CONFIG_X86_RDC321X is not set
+# CONFIG_X86_REBOOTFIXUPS is not set
+CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS=y
+CONFIG_X86_RESERVE_LOW=64
+# CONFIG_X86_SPEEDSTEP_CENTRINO is not set
+# CONFIG_X86_SPEEDSTEP_ICH is not set
+# CONFIG_X86_SPEEDSTEP_LIB is not set
+# CONFIG_X86_SPEEDSTEP_SMI is not set
+CONFIG_X86_THERMAL_VECTOR=y
+CONFIG_X86_TSC=y
+CONFIG_X86_USE_PPRO_CHECKSUM=y
+CONFIG_X86_VERBOSE_BOOTUP=y
+CONFIG_X86_WP_WORKS_OK=y
+CONFIG_X86_XADD=y
+CONFIG_XFRM_USER=y
+# CONFIG_XO15_EBOOK is not set
+CONFIG_ZONE_DMA=y
+# CONFIG_ZONE_DMA32 is not set
+CONFIG_ZONE_DMA_FLAG=1
diff --git a/chromeos/config/i386/config.flavour.chromeos-intel-menlow b/chromeos/config/i386/config.flavour.chromeos-intel-menlow
new file mode 120000
index 000000000000..c867d1c41632
--- /dev/null
+++ b/chromeos/config/i386/config.flavour.chromeos-intel-menlow
@@ -0,0 +1 @@
+config.flavour.chromeos-pinetrail-i386 \ No newline at end of file
diff --git a/chromeos/config/i386/config.flavour.chromeos-pinetrail-i386 b/chromeos/config/i386/config.flavour.chromeos-pinetrail-i386
new file mode 100644
index 000000000000..9a9d2991c3fd
--- /dev/null
+++ b/chromeos/config/i386/config.flavour.chromeos-pinetrail-i386
@@ -0,0 +1,41 @@
+#
+# Config options generated by splitconfig
+#
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+CONFIG_ACPI_WMI=m
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ATL1 is not set
+# CONFIG_ATL1C is not set
+# CONFIG_ATL1E is not set
+# CONFIG_ATL2 is not set
+# CONFIG_B44 is not set
+# CONFIG_BRCMSMAC is not set
+# CONFIG_BRCMUTIL is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_DRM_NOUVEAU is not set
+# CONFIG_DRM_RADEON is not set
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_IWL3945 is not set
+# CONFIG_IWL4965 is not set
+# CONFIG_IWLAGN is not set
+# CONFIG_MXM_WMI is not set
+# CONFIG_PCNET32 is not set
+# CONFIG_R8169 is not set
+# CONFIG_RT2500USB is not set
+# CONFIG_RT2800USB is not set
+# CONFIG_RT73USB is not set
+CONFIG_RTL8192CE=m
+CONFIG_RTL8192C_COMMON=m
+CONFIG_RTLWIFI=m
+# CONFIG_SKY2 is not set
+# CONFIG_SSB is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_X86_POWERNOW_K6 is not set
+# CONFIG_X86_POWERNOW_K7 is not set
+# CONFIG_X86_POWERNOW_K8 is not set
+# CONFIG_ZD1211RW is not set
diff --git a/chromeos/config/i386/config.flavour.chromiumos-i386 b/chromeos/config/i386/config.flavour.chromiumos-i386
new file mode 100644
index 000000000000..244efff4d3ab
--- /dev/null
+++ b/chromeos/config/i386/config.flavour.chromiumos-i386
@@ -0,0 +1,85 @@
+#
+# Config options generated by splitconfig
+#
+CONFIG_8139CP=m
+CONFIG_8139TOO=m
+# CONFIG_8139TOO_8129 is not set
+CONFIG_8139TOO_PIO=y
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139_OLD_RX_RESET is not set
+CONFIG_ACPI_WMI=y
+CONFIG_AMD8111_ETH=m
+CONFIG_ATL1=m
+CONFIG_ATL1C=m
+CONFIG_ATL1E=m
+CONFIG_ATL2=m
+CONFIG_B44=m
+CONFIG_B44_PCI=y
+CONFIG_B44_PCICORE_AUTOSELECT=y
+CONFIG_B44_PCI_AUTOSELECT=y
+# CONFIG_BRCMDBG is not set
+CONFIG_BRCMSMAC=m
+CONFIG_BRCMUTIL=m
+CONFIG_BROADCOM_PHY=y
+CONFIG_DRM_NOUVEAU=y
+CONFIG_DRM_NOUVEAU_BACKLIGHT=y
+# CONFIG_DRM_NOUVEAU_DEBUG is not set
+CONFIG_DRM_RADEON=y
+CONFIG_DRM_RADEON_KMS=y
+CONFIG_DRM_TTM=y
+CONFIG_EXTRA_FIRMWARE="radeon/PALM_me.bin radeon/PALM_pfp.bin radeon/SUMO_rlc.bin"
+CONFIG_EXTRA_FIRMWARE_DIR="firmware"
+CONFIG_FB_BACKLIGHT=y
+CONFIG_FORCEDETH=m
+CONFIG_IWL3945=m
+CONFIG_IWL4965=m
+CONFIG_IWLAGN=m
+# CONFIG_IWLWIFI_DEBUG is not set
+# CONFIG_IWLWIFI_DEBUGFS is not set
+# CONFIG_IWLWIFI_DEVICE_SVTOOL is not set
+# CONFIG_IWLWIFI_DEVICE_TRACING is not set
+CONFIG_IWLWIFI_LEGACY=m
+# CONFIG_IWLWIFI_LEGACY_DEBUG is not set
+# CONFIG_IWLWIFI_LEGACY_DEBUGFS is not set
+# CONFIG_IWLWIFI_LEGACY_DEVICE_TRACING is not set
+# CONFIG_IWL_P2P is not set
+CONFIG_MXM_WMI=y
+CONFIG_PCNET32=m
+CONFIG_R8169=m
+CONFIG_RT2500USB=m
+CONFIG_RT2800USB=m
+CONFIG_RT2800USB_RT33XX=y
+CONFIG_RT2800USB_RT35XX=y
+# CONFIG_RT2800USB_RT53XX is not set
+# CONFIG_RT2800USB_UNKNOWN is not set
+CONFIG_RT2800_LIB=m
+# CONFIG_RT2X00_DEBUG is not set
+CONFIG_RT2X00_LIB=m
+CONFIG_RT2X00_LIB_CRYPTO=y
+# CONFIG_RT2X00_LIB_DEBUGFS is not set
+CONFIG_RT2X00_LIB_FIRMWARE=y
+CONFIG_RT2X00_LIB_LEDS=y
+CONFIG_RT2X00_LIB_USB=m
+CONFIG_RT73USB=m
+# CONFIG_RTL8192CE is not set
+CONFIG_SKY2=m
+# CONFIG_SKY2_DEBUG is not set
+CONFIG_SSB=m
+# CONFIG_SSB_B43_PCI_BRIDGE is not set
+# CONFIG_SSB_DEBUG is not set
+CONFIG_SSB_DRIVER_PCICORE=y
+CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y
+CONFIG_SSB_PCIHOST=y
+CONFIG_SSB_PCIHOST_POSSIBLE=y
+# CONFIG_SSB_SILENT is not set
+CONFIG_SSB_SPROM=y
+CONFIG_TIGON3=m
+CONFIG_USB_RTL8150=m
+CONFIG_VIA_RHINE=m
+# CONFIG_VIA_RHINE_MMIO is not set
+CONFIG_X86_POWERNOW_K6=y
+CONFIG_X86_POWERNOW_K7=y
+CONFIG_X86_POWERNOW_K7_ACPI=y
+CONFIG_X86_POWERNOW_K8=y
+CONFIG_ZD1211RW=m
+# CONFIG_ZD1211RW_DEBUG is not set
diff --git a/chromeos/config/x86_64/config.common.x86_64 b/chromeos/config/x86_64/config.common.x86_64
new file mode 100644
index 000000000000..eab255dbd9e2
--- /dev/null
+++ b/chromeos/config/x86_64/config.common.x86_64
@@ -0,0 +1,743 @@
+#
+# Config options generated by splitconfig
+#
+CONFIG_64BIT=y
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_ACERHDF is not set
+# CONFIG_ACER_WMI is not set
+CONFIG_ACPI=y
+CONFIG_ACPI_AC=y
+# CONFIG_ACPI_APEI is not set
+# CONFIG_ACPI_ASUS is not set
+CONFIG_ACPI_BATTERY=y
+CONFIG_ACPI_BLACKLIST_YEAR=0
+CONFIG_ACPI_BUTTON=y
+# CONFIG_ACPI_CMPC is not set
+CONFIG_ACPI_CONTAINER=y
+# CONFIG_ACPI_CUSTOM_DSDT is not set
+# CONFIG_ACPI_CUSTOM_METHOD is not set
+# CONFIG_ACPI_DEBUG is not set
+CONFIG_ACPI_DOCK=y
+# CONFIG_ACPI_EC_DEBUGFS is not set
+CONFIG_ACPI_FAN=y
+# CONFIG_ACPI_HED is not set
+CONFIG_ACPI_HOTPLUG_CPU=y
+# CONFIG_ACPI_PCI_SLOT is not set
+CONFIG_ACPI_PROCESSOR=y
+# CONFIG_ACPI_PROCESSOR_AGGREGATOR is not set
+CONFIG_ACPI_PROCFS=y
+CONFIG_ACPI_PROCFS_POWER=y
+CONFIG_ACPI_PROC_EVENT=y
+# CONFIG_ACPI_QUICKSTART is not set
+# CONFIG_ACPI_SBS is not set
+CONFIG_ACPI_SLEEP=y
+CONFIG_ACPI_THERMAL=y
+# CONFIG_ACPI_TOSHIBA is not set
+CONFIG_ACPI_VIDEO=y
+CONFIG_ACPI_WMI=m
+# CONFIG_ADAPTEC_STARFIRE is not set
+CONFIG_AGP=y
+# CONFIG_AGP_AMD64 is not set
+CONFIG_AGP_INTEL=y
+# CONFIG_AGP_SIS is not set
+# CONFIG_AGP_VIA is not set
+# CONFIG_AIRO is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_AMD_IOMMU is not set
+CONFIG_AMD_NB=y
+CONFIG_ANDROID_PARANOID_NETWORK=y
+CONFIG_ARCH_CLOCKSOURCE_DATA=y
+CONFIG_ARCH_CPU_PROBE_RELEASE=y
+CONFIG_ARCH_DEFCONFIG="arch/x86/configs/x86_64_defconfig"
+CONFIG_ARCH_DMA_ADDR_T_64BIT=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y
+CONFIG_ARCH_HAS_CPU_RELAX=y
+CONFIG_ARCH_HAS_DEFAULT_IDLE=y
+CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_HWEIGHT_CFLAGS="-fcall-saved-rdi -fcall-saved-rsi -fcall-saved-rdx -fcall-saved-rcx -fcall-saved-r8 -fcall-saved-r9 -fcall-saved-r10 -fcall-saved-r11"
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_ARCH_PROC_KCORE_TEXT=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
+CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y
+CONFIG_ARCH_SUPPORTS_MSI=y
+CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y
+CONFIG_ARCH_USES_PG_UNCACHED=y
+CONFIG_ARCH_WANT_FRAME_POINTERS=y
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+# CONFIG_ASUS_LAPTOP is not set
+# CONFIG_ASUS_WMI is not set
+CONFIG_ATA=y
+CONFIG_ATA_ACPI=y
+CONFIG_ATA_BMDMA=y
+CONFIG_ATA_GENERIC=y
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_ATA_PIIX=y
+CONFIG_ATA_SFF=y
+CONFIG_ATA_VERBOSE_ERROR=y
+CONFIG_ATH5K=m
+# CONFIG_ATH5K_DEBUG is not set
+CONFIG_ATH5K_PCI=y
+# CONFIG_ATH5K_TRACER is not set
+CONFIG_ATH9K=m
+# CONFIG_ATH9K_AHB is not set
+CONFIG_ATH9K_COMMON=m
+CONFIG_ATH9K_DEBUGFS=y
+CONFIG_ATH9K_HW=m
+CONFIG_ATH9K_PCI=y
+CONFIG_ATH9K_RATE_CONTROL=y
+# CONFIG_ATL1 is not set
+# CONFIG_ATL1C is not set
+# CONFIG_ATL1E is not set
+# CONFIG_ATL2 is not set
+CONFIG_AUDIT_ARCH=y
+# CONFIG_B44 is not set
+# CONFIG_BACKLIGHT_APPLE is not set
+# CONFIG_BACKLIGHT_PROGEAR is not set
+# CONFIG_BACKLIGHT_SAHARA is not set
+# CONFIG_BATTERY_BQ20Z75 is not set
+# CONFIG_BATTERY_BQ27x00 is not set
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_BLOCK_COMPAT=y
+# CONFIG_BPF_JIT is not set
+# CONFIG_BRCMSMAC is not set
+# CONFIG_BRCMUTIL is not set
+# CONFIG_BROADCOM_PHY is not set
+CONFIG_BT_ATH3K=m
+CONFIG_BT_HCIBCM203X=m
+CONFIG_BT_HCIBPA10X=m
+# CONFIG_BT_HCIUART is not set
+# CONFIG_CALGARY_IOMMU is not set
+# CONFIG_CHARGER_GPIO is not set
+CONFIG_CHECK_SIGNATURE=y
+CONFIG_CLKBLD_I8253=y
+CONFIG_CLKEVT_I8253=y
+CONFIG_CLOCKSOURCE_WATCHDOG=y
+# CONFIG_CMDLINE_BOOL is not set
+CONFIG_CMPXCHG_DOUBLE=y
+CONFIG_CMPXCHG_LOCAL=y
+# CONFIG_COMEDI is not set
+# CONFIG_COMPAL_LAPTOP is not set
+CONFIG_COMPAT=y
+CONFIG_COMPAT_BINFMT_ELF=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_COMPAT_FOR_U64_ALIGNMENT=y
+CONFIG_COMPAT_NETLINK_MESSAGES=y
+# CONFIG_COMPAT_VDSO is not set
+CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
+# CONFIG_CPA_DEBUG is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_SUP_AMD=y
+CONFIG_CPU_SUP_CENTAUR=y
+CONFIG_CPU_SUP_INTEL=y
+# CONFIG_CRASH_DUMP is not set
+CONFIG_CRYPTO_AES_NI_INTEL=m
+CONFIG_CRYPTO_AES_X86_64=m
+# CONFIG_CRYPTO_CRC32C_INTEL is not set
+CONFIG_CRYPTO_CRYPTD=m
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_DEV_PADLOCK is not set
+# CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL is not set
+# CONFIG_CRYPTO_SALSA20_X86_64 is not set
+# CONFIG_CRYPTO_TWOFISH_X86_64 is not set
+# CONFIG_DCDBAS is not set
+CONFIG_DEBUG_BOOT_PARAMS=y
+# CONFIG_DEBUG_NX_TEST is not set
+CONFIG_DEBUG_RODATA=y
+# CONFIG_DEBUG_RODATA_TEST is not set
+# CONFIG_DEBUG_SET_MODULE_RONX is not set
+CONFIG_DEBUG_STACKOVERFLOW=y
+# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set
+# CONFIG_DEBUG_VIRTUAL is not set
+CONFIG_DEFAULT_IO_DELAY_TYPE=0
+# CONFIG_DELL_RBU is not set
+CONFIG_DELL_WMI=m
+# CONFIG_DELL_WMI_AIO is not set
+CONFIG_DIRECT_GBPAGES=y
+CONFIG_DMI=y
+CONFIG_DMIID=y
+# CONFIG_DMI_SYSFS is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_DNS_RESOLVER is not set
+CONFIG_DRM=y
+# CONFIG_DRM_I2C_CH7006 is not set
+# CONFIG_DRM_I2C_SIL164 is not set
+# CONFIG_DRM_I810 is not set
+CONFIG_DRM_I915=y
+CONFIG_DRM_I915_KMS=y
+CONFIG_DRM_KMS_HELPER=y
+# CONFIG_DRM_MGA is not set
+# CONFIG_DRM_NOUVEAU is not set
+# CONFIG_DRM_PSB is not set
+# CONFIG_DRM_R128 is not set
+# CONFIG_DRM_RADEON is not set
+# CONFIG_DRM_SAVAGE is not set
+# CONFIG_DRM_SIS is not set
+# CONFIG_DRM_TDFX is not set
+# CONFIG_DRM_VIA is not set
+# CONFIG_DRM_VMWGFX is not set
+CONFIG_E100=m
+CONFIG_E1000=m
+CONFIG_E1000E=m
+CONFIG_EARLY_PRINTK_DBGP=y
+# CONFIG_EDAC is not set
+# CONFIG_EDD is not set
+# CONFIG_EEEPC_LAPTOP is not set
+CONFIG_EFI=y
+# CONFIG_EFI_VARS is not set
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_EPIC100 is not set
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_FB_ARC is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_EFI is not set
+# CONFIG_FB_GEODE is not set
+# CONFIG_FB_HGA is not set
+# CONFIG_FB_LE80578 is not set
+# CONFIG_FB_N411 is not set
+# CONFIG_FB_VESA is not set
+# CONFIG_FB_VGA16 is not set
+# CONFIG_FB_VIA is not set
+# CONFIG_FEALNX is not set
+CONFIG_FIRMWARE_MEMMAP=y
+CONFIG_FIX_EARLYCON_MEM=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x16=y
+CONFIG_FONT_8x8=y
+# CONFIG_FORCEDETH is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FRAME_WARN=2048
+CONFIG_FTRACE_NMI_ENTER=y
+CONFIG_FTRACE_SYSCALLS=y
+# CONFIG_FUJITSU_LAPTOP is not set
+CONFIG_FUNCTION_GRAPH_TRACER=y
+CONFIG_GART_IOMMU=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_CPU=y
+CONFIG_GENERIC_FIND_FIRST_BIT=y
+CONFIG_GENERIC_IOMAP=y
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_GENERIC_PENDING_IRQ=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+# CONFIG_GOOGLE_FIRMWARE is not set
+# CONFIG_GPIO_LANGWELL is not set
+# CONFIG_GPIO_PCH is not set
+# CONFIG_GPIO_SCH is not set
+# CONFIG_HANGCHECK_TIMER is not set
+CONFIG_HARDLOCKUP_DETECTOR=y
+# CONFIG_HAVE_AOUT is not set
+CONFIG_HAVE_ARCH_JUMP_LABEL=y
+CONFIG_HAVE_ARCH_KMEMCHECK=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_BPF_JIT=y
+CONFIG_HAVE_CPUMASK_OF_CPU_MAP=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_HAVE_FTRACE_NMI_ENTER=y
+CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST=y
+CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_HAVE_IOREMAP_PROT=y
+CONFIG_HAVE_KERNEL_BZIP2=y
+CONFIG_HAVE_KERNEL_XZ=y
+CONFIG_HAVE_KVM=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_HAVE_MEMORY_PRESENT=y
+CONFIG_HAVE_MIXED_BREAKPOINTS_REGS=y
+CONFIG_HAVE_MMIOTRACE_SUPPORT=y
+CONFIG_HAVE_OPTPROBES=y
+CONFIG_HAVE_PCSPKR_PLATFORM=y
+CONFIG_HAVE_PERF_EVENTS_NMI=y
+CONFIG_HAVE_SETUP_PER_CPU_AREA=y
+CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
+CONFIG_HAVE_TEXT_POKE_SMP=y
+CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y
+CONFIG_HAVE_USER_RETURN_NOTIFIER=y
+CONFIG_HID_MICROSOFT=m
+CONFIG_HID_PID=y
+CONFIG_HOSTAP_PCI=m
+CONFIG_HOSTAP_PLX=m
+CONFIG_HOTPLUG_PCI=y
+# CONFIG_HOTPLUG_PCI_ACPI is not set
+# CONFIG_HOTPLUG_PCI_CPCI is not set
+# CONFIG_HOTPLUG_PCI_FAKE is not set
+CONFIG_HOTPLUG_PCI_PCIE=y
+# CONFIG_HOTPLUG_PCI_SHPC is not set
+CONFIG_HPET=y
+CONFIG_HPET_EMULATE_RTC=y
+# CONFIG_HPET_MMAP is not set
+CONFIG_HPET_TIMER=y
+# CONFIG_HP_ACCEL is not set
+CONFIG_HP_WMI=m
+CONFIG_HT_IRQ=y
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HW_RANDOM_AMD is not set
+CONFIG_HW_RANDOM_INTEL=y
+# CONFIG_HW_RANDOM_VIA is not set
+# CONFIG_HW_RANDOM_VIRTIO is not set
+# CONFIG_HYPERV is not set
+CONFIG_HZ=1000
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_1000=y
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
+CONFIG_I2C_ALGOBIT=y
+CONFIG_I2C_I801=m
+CONFIG_I2C_PIIX4=m
+# CONFIG_I2C_SCMI is not set
+# CONFIG_I7300_IDLE is not set
+# CONFIG_I8K is not set
+# CONFIG_IA32_AOUT is not set
+CONFIG_IA32_EMULATION=y
+# CONFIG_IBM_ASM is not set
+# CONFIG_IBM_RTL is not set
+# CONFIG_IDEAPAD_LAPTOP is not set
+# CONFIG_IDE_PHISON is not set
+CONFIG_IGBVF=m
+CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000
+# CONFIG_INPUT_APANEL is not set
+# CONFIG_INPUT_ATLAS_BTNS is not set
+CONFIG_INPUT_SPARSEKMAP=m
+CONFIG_INSTRUCTION_DECODER=y
+# CONFIG_INTEL_IDLE is not set
+# CONFIG_INTEL_IOMMU is not set
+# CONFIG_INTEL_IPS is not set
+# CONFIG_INTEL_MEI is not set
+CONFIG_INTEL_MENLOW=m
+# CONFIG_INTEL_OAKTRAIL is not set
+# CONFIG_IOMMU_DEBUG is not set
+CONFIG_IOMMU_HELPER=y
+# CONFIG_IOMMU_STRESS is not set
+CONFIG_IO_DELAY_0X80=y
+# CONFIG_IO_DELAY_0XED is not set
+# CONFIG_IO_DELAY_NONE is not set
+CONFIG_IO_DELAY_TYPE_0X80=0
+CONFIG_IO_DELAY_TYPE_0XED=1
+CONFIG_IO_DELAY_TYPE_NONE=3
+CONFIG_IO_DELAY_TYPE_UDELAY=2
+# CONFIG_IO_DELAY_UDELAY is not set
+CONFIG_IPV6=m
+# CONFIG_IP_PNP is not set
+CONFIG_IRQ_FORCED_THREADING=y
+# CONFIG_IRQ_REMAP is not set
+# CONFIG_IRQ_TIME_ACCOUNTING is not set
+# CONFIG_IR_ENE is not set
+# CONFIG_IR_FINTEK is not set
+# CONFIG_IR_IMON is not set
+# CONFIG_IR_ITE_CIR is not set
+# CONFIG_IR_JVC_DECODER is not set
+# CONFIG_IR_LIRC_CODEC is not set
+# CONFIG_IR_MCEUSB is not set
+CONFIG_IR_MCE_KBD_DECODER=m
+# CONFIG_IR_NEC_DECODER is not set
+# CONFIG_IR_NUVOTON is not set
+# CONFIG_IR_RC5_DECODER is not set
+# CONFIG_IR_RC5_SZ_DECODER is not set
+# CONFIG_IR_RC6_DECODER is not set
+# CONFIG_IR_REDRAT3 is not set
+# CONFIG_IR_SONY_DECODER is not set
+# CONFIG_IR_STREAMZAP is not set
+# CONFIG_IR_WINBOND_CIR is not set
+CONFIG_ISA_DMA_API=y
+# CONFIG_ISCSI_IBFT_FIND is not set
+CONFIG_IWL3945=m
+CONFIG_IWL4965=m
+CONFIG_IWLAGN=m
+# CONFIG_IWLWIFI_DEBUG is not set
+# CONFIG_IWLWIFI_DEBUGFS is not set
+# CONFIG_IWLWIFI_DEVICE_SVTOOL is not set
+# CONFIG_IWLWIFI_DEVICE_TRACING is not set
+CONFIG_IWLWIFI_LEGACY=m
+# CONFIG_IWLWIFI_LEGACY_DEBUG is not set
+# CONFIG_IWLWIFI_LEGACY_DEBUGFS is not set
+# CONFIG_IWLWIFI_LEGACY_DEVICE_TRACING is not set
+# CONFIG_IWL_P2P is not set
+CONFIG_JME=m
+# CONFIG_JUMP_LABEL is not set
+# CONFIG_KERNEL_BZIP2 is not set
+# CONFIG_KERNEL_XZ is not set
+CONFIG_KEYS_COMPAT=y
+# CONFIG_KSZ884X_PCI is not set
+# CONFIG_KTIME_SCALAR is not set
+# CONFIG_KVM is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_LEDS_ALIX2 is not set
+# CONFIG_LEDS_CLEVO_MAIL is not set
+# CONFIG_LEDS_DELL_NETBOOKS is not set
+# CONFIG_LEDS_INTEL_SS4200 is not set
+CONFIG_LIBERTAS_THINFIRM_USB=m
+CONFIG_LIRC=m
+# CONFIG_LIRC_STAGING is not set
+CONFIG_LPC_SCH=m
+# CONFIG_MAC80211_MESH is not set
+# CONFIG_MACINTOSH_DRIVERS is not set
+# CONFIG_MATOM is not set
+# CONFIG_MAXSMP is not set
+# CONFIG_MCORE2 is not set
+# CONFIG_MEMORY_FAILURE is not set
+# CONFIG_MEMORY_HOTPLUG is not set
+# CONFIG_MEMTEST is not set
+CONFIG_MFD_CORE=m
+# CONFIG_MFD_CS5535 is not set
+# CONFIG_MFD_TPS6586X is not set
+# CONFIG_MFD_TPS6591X is not set
+CONFIG_MICROCODE=y
+CONFIG_MICROCODE_AMD=y
+CONFIG_MICROCODE_INTEL=y
+CONFIG_MICROCODE_OLD_INTERFACE=y
+# CONFIG_MK8 is not set
+# CONFIG_MMC is not set
+# CONFIG_MMIOTRACE is not set
+CONFIG_MOUSE_APPLETOUCH=m
+CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_ELANTECH=y
+CONFIG_MOUSE_PS2_LIFEBOOK=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+# CONFIG_MOUSE_PS2_SENTELIC is not set
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MPSC is not set
+# CONFIG_MSI_LAPTOP is not set
+# CONFIG_MSI_WMI is not set
+CONFIG_MTRR=y
+# CONFIG_MTRR_SANITIZER is not set
+# CONFIG_MWAVE is not set
+# CONFIG_MXM_WMI is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y
+CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
+CONFIG_NEED_SG_DMA_LENGTH=y
+# CONFIG_NETWORK_FILESYSTEMS is not set
+CONFIG_NET_PCI=y
+# CONFIG_NET_SB1000 is not set
+CONFIG_NO_BOOTMEM=y
+CONFIG_NR_CPUS=4
+# CONFIG_NUMA is not set
+CONFIG_NVRAM=y
+CONFIG_OPTIMIZE_INLINING=y
+CONFIG_OUTPUT_FORMAT="elf64-x86-64"
+CONFIG_PAGEFLAGS_EXTENDED=y
+# CONFIG_PANASONIC_LAPTOP is not set
+# CONFIG_PARAVIRT_GUEST is not set
+# CONFIG_PATA_ACPI is not set
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_ATP867X is not set
+# CONFIG_PATA_CMD640_PCI is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CS5536 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_LEGACY is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NINJA32 is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_NS87415 is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_PLATFORM is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RDC is not set
+# CONFIG_PATA_RZ1000 is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SCH is not set
+# CONFIG_PATA_SERVERWORKS is not set
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_TOSHIBA is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+CONFIG_PCIEAER=y
+# CONFIG_PCIEAER_INJECT is not set
+CONFIG_PCIEASPM=y
+# CONFIG_PCIEASPM_DEBUG is not set
+CONFIG_PCIEASPM_DEFAULT=y
+# CONFIG_PCIEASPM_PERFORMANCE is not set
+# CONFIG_PCIEASPM_POWERSAVE is not set
+CONFIG_PCIEPORTBUS=y
+# CONFIG_PCIE_ECRC is not set
+CONFIG_PCIE_PME=y
+# CONFIG_PCI_CNB20LE_QUIRK is not set
+CONFIG_PCI_DIRECT=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_IOAPIC=y
+CONFIG_PCI_LABEL=y
+CONFIG_PCI_MMCONFIG=y
+CONFIG_PCI_MSI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_PCSPKR_PLATFORM is not set
+# CONFIG_PDC_ADMA is not set
+CONFIG_PHYSICAL_ALIGN=0x1000000
+CONFIG_PHYSICAL_START=0x1000000
+CONFIG_PHYS_ADDR_T_64BIT=y
+CONFIG_PM_TRACE=y
+CONFIG_PM_TRACE_RTC=y
+CONFIG_PNP=y
+CONFIG_PNPACPI=y
+CONFIG_PNP_DEBUG_MESSAGES=y
+# CONFIG_PROCESSOR_SELECT is not set
+CONFIG_PROC_KCORE=y
+CONFIG_PROVIDE_OHCI1394_DMA_INIT=y
+# CONFIG_R6040 is not set
+# CONFIG_R8169 is not set
+# CONFIG_RAPIDIO is not set
+CONFIG_RC_CORE=m
+# CONFIG_RC_LOOPBACK is not set
+CONFIG_RC_MAP=m
+CONFIG_REALTEK_AUTOPM=y
+# CONFIG_REGULATOR is not set
+# CONFIG_RELOCATABLE is not set
+# CONFIG_REPORT_PRESENT_CPUS is not set
+# CONFIG_RT2500USB is not set
+# CONFIG_RT2800USB is not set
+# CONFIG_RT73USB is not set
+CONFIG_RTC_DRV_CMOS=m
+# CONFIG_RTC_HCTOSYS is not set
+CONFIG_RTL8192CE=m
+CONFIG_RTL8192C_COMMON=m
+CONFIG_RTLWIFI=m
+# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+# CONFIG_SAMSUNG_LAPTOP is not set
+# CONFIG_SAMSUNG_Q10 is not set
+# CONFIG_SATA_ACARD_AHCI is not set
+CONFIG_SATA_AHCI=y
+# CONFIG_SATA_AHCI_PLATFORM is not set
+# CONFIG_SATA_INIC162X is not set
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
+# CONFIG_SATA_PMP is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_SIL is not set
+# CONFIG_SATA_SIL24 is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_SVW is not set
+# CONFIG_SATA_SX4 is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
+# CONFIG_SC92031 is not set
+CONFIG_SCHED_HRTICK=y
+CONFIG_SCHED_MC=y
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+CONFIG_SCHED_SMT=y
+CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOWLEVEL is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ABITUGURU3 is not set
+# CONFIG_SENSORS_ACPI_POWER is not set
+# CONFIG_SENSORS_APPLESMC is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATK0110 is not set
+CONFIG_SENSORS_CORETEMP=y
+# CONFIG_SENSORS_FAM15H_POWER is not set
+# CONFIG_SENSORS_FSCHMD is not set
+# CONFIG_SENSORS_HDAPS is not set
+# CONFIG_SENSORS_ISL29018 is not set
+# CONFIG_SENSORS_ISL29028 is not set
+# CONFIG_SENSORS_K10TEMP is not set
+# CONFIG_SENSORS_K8TEMP is not set
+# CONFIG_SENSORS_NCT1008 is not set
+# CONFIG_SENSORS_VIA_CPUTEMP is not set
+# CONFIG_SERIAL_8250 is not set
+CONFIG_SERIO_CT82C710=m
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_PCIPS2=m
+# CONFIG_SFI is not set
+# CONFIG_SIGMA is not set
+# CONFIG_SIS900 is not set
+# CONFIG_SKY2 is not set
+# CONFIG_SLAB is not set
+# CONFIG_SLICOSS is not set
+CONFIG_SLUB=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+# CONFIG_SMSC9420 is not set
+# CONFIG_SND_ALS4000 is not set
+# CONFIG_SND_ASIHPI is not set
+# CONFIG_SND_CS5530 is not set
+CONFIG_SND_DMA_SGBUF=y
+CONFIG_SND_HDA_CODEC_ANALOG=y
+CONFIG_SND_HDA_CODEC_CA0110=y
+CONFIG_SND_HDA_CODEC_CA0132=y
+CONFIG_SND_HDA_CODEC_CIRRUS=y
+CONFIG_SND_HDA_CODEC_CMEDIA=y
+CONFIG_SND_HDA_CODEC_CONEXANT=y
+CONFIG_SND_HDA_CODEC_HDMI=y
+CONFIG_SND_HDA_CODEC_REALTEK=y
+CONFIG_SND_HDA_CODEC_SI3054=y
+CONFIG_SND_HDA_CODEC_SIGMATEL=y
+CONFIG_SND_HDA_CODEC_VIA=y
+CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS=y
+CONFIG_SND_HDA_GENERIC=y
+CONFIG_SND_HDA_HWDEP=y
+# CONFIG_SND_HDA_INPUT_BEEP is not set
+CONFIG_SND_HDA_INPUT_JACK=y
+CONFIG_SND_HDA_INTEL=m
+# CONFIG_SND_HDA_PATCH_LOADER is not set
+# CONFIG_SND_HDA_PLATFORM_DRIVER is not set
+CONFIG_SND_HDA_POWER_SAVE=y
+CONFIG_SND_HDA_POWER_SAVE_DEFAULT=5
+CONFIG_SND_HDA_PREALLOC_SIZE=64
+# CONFIG_SND_HDA_RECONFIG is not set
+CONFIG_SND_PCM=m
+# CONFIG_SND_SOC is not set
+CONFIG_SND_TIMER=m
+# CONFIG_SND_USB_US122L is not set
+# CONFIG_SND_USB_USX2Y is not set
+CONFIG_SND_VMASTER=y
+# CONFIG_SOC_CAMERA is not set
+# CONFIG_SONY_LAPTOP is not set
+CONFIG_SPARSEMEM=y
+CONFIG_SPARSEMEM_ALLOC_MEM_MAP_TOGETHER=y
+CONFIG_SPARSEMEM_EXTREME=y
+CONFIG_SPARSEMEM_MANUAL=y
+CONFIG_SPARSEMEM_VMEMMAP=y
+CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
+CONFIG_SPARSE_IRQ=y
+# CONFIG_SQUASHFS is not set
+# CONFIG_SSB is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_SWAP is not set
+CONFIG_SWIOTLB=y
+CONFIG_SYSVIPC_COMPAT=y
+# CONFIG_TCG_INFINEON is not set
+CONFIG_TCG_TIS=y
+# CONFIG_TELCLOCK is not set
+# CONFIG_THINKPAD_ACPI is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_TLAN is not set
+# CONFIG_TOPSTAR_LAPTOP is not set
+# CONFIG_TOSHIBA_BT_RFKILL is not set
+# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set
+# CONFIG_TRANSPARENT_HUGEPAGE is not set
+CONFIG_USB_NET_AX8817X=m
+CONFIG_USB_NET_CDCETHER=m
+CONFIG_USB_NET_CDC_NCM=m
+CONFIG_USB_NET_DM9601=m
+CONFIG_USB_NET_MCS7830=m
+CONFIG_USB_NET_NET1080=m
+CONFIG_USB_NET_SMSC95XX=m
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_RTL8150 is not set
+CONFIG_USB_STORAGE_REALTEK=y
+CONFIG_USB_UHCI_HCD=y
+CONFIG_USB_USBNET=m
+CONFIG_USER_STACKTRACE_SUPPORT=y
+# CONFIG_VGACON_SOFT_SCROLLBACK is not set
+# CONFIG_VGA_ARB is not set
+CONFIG_VGA_CONSOLE=y
+# CONFIG_VGA_SWITCHEROO is not set
+# CONFIG_VHOST_NET is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_VIDEO_BT848 is not set
+# CONFIG_VIDEO_CX231XX is not set
+# CONFIG_VIDEO_CX88 is not set
+# CONFIG_VIDEO_GO7007 is not set
+# CONFIG_VIDEO_IR_I2C is not set
+# CONFIG_VIDEO_IVTV is not set
+# CONFIG_VIDEO_TM6000 is not set
+# CONFIG_VIDEO_VIVI is not set
+# CONFIG_VIDEO_ZORAN is not set
+CONFIG_VIRTIO=m
+CONFIG_VIRTIO_BLK=m
+# CONFIG_VIRTIO_CONSOLE is not set
+CONFIG_VIRTIO_NET=m
+CONFIG_VIRTIO_PCI=m
+CONFIG_VIRTIO_RING=m
+CONFIG_VIRTUALIZATION=y
+# CONFIG_VMWARE_BALLOON is not set
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_X86=y
+# CONFIG_X86_32 is not set
+CONFIG_X86_64=y
+CONFIG_X86_64_SMP=y
+CONFIG_X86_ACPI_CPUFREQ=y
+CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK=y
+CONFIG_X86_CHECK_BIOS_CORRUPTION=y
+CONFIG_X86_CMOV=y
+CONFIG_X86_CMPXCHG=y
+CONFIG_X86_CMPXCHG64=y
+CONFIG_X86_CPUID=y
+CONFIG_X86_DEBUGCTLMSR=y
+CONFIG_X86_EXTENDED_PLATFORM=y
+CONFIG_X86_HT=y
+CONFIG_X86_INTERNODE_CACHE_SHIFT=6
+CONFIG_X86_IO_APIC=y
+CONFIG_X86_L1_CACHE_SHIFT=6
+CONFIG_X86_LOCAL_APIC=y
+CONFIG_X86_MCE=y
+# CONFIG_X86_MCE_AMD is not set
+# CONFIG_X86_MCE_INJECT is not set
+CONFIG_X86_MCE_INTEL=y
+CONFIG_X86_MCE_THRESHOLD=y
+CONFIG_X86_MINIMUM_CPU_FAMILY=64
+CONFIG_X86_MPPARSE=y
+CONFIG_X86_MSR=y
+# CONFIG_X86_P4_CLOCKMOD is not set
+CONFIG_X86_PAT=y
+# CONFIG_X86_PCC_CPUFREQ is not set
+CONFIG_X86_PLATFORM_DEVICES=y
+CONFIG_X86_PM_TIMER=y
+# CONFIG_X86_POWERNOW_K8 is not set
+# CONFIG_X86_PTDUMP is not set
+CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS=y
+CONFIG_X86_RESERVE_LOW=64
+# CONFIG_X86_SPEEDSTEP_CENTRINO is not set
+# CONFIG_X86_SPEEDSTEP_LIB is not set
+CONFIG_X86_SUPPORTS_MEMORY_FAILURE=y
+CONFIG_X86_THERMAL_VECTOR=y
+CONFIG_X86_TSC=y
+CONFIG_X86_VERBOSE_BOOTUP=y
+# CONFIG_X86_VSMP is not set
+CONFIG_X86_WP_WORKS_OK=y
+CONFIG_X86_XADD=y
+CONFIG_XFRM_USER=y
+# CONFIG_XO15_EBOOK is not set
+# CONFIG_ZD1211RW is not set
+CONFIG_ZONE_DMA=y
+CONFIG_ZONE_DMA32=y
+CONFIG_ZONE_DMA_FLAG=1
diff --git a/chromeos/config/x86_64/config.flavour.chromeos-intel-pineview b/chromeos/config/x86_64/config.flavour.chromeos-intel-pineview
new file mode 100644
index 000000000000..fad4bbee31e2
--- /dev/null
+++ b/chromeos/config/x86_64/config.flavour.chromeos-intel-pineview
@@ -0,0 +1,3 @@
+#
+# Config options generated by splitconfig
+#
diff --git a/chromeos/scripts/allconfigs b/chromeos/scripts/allconfigs
new file mode 100755
index 000000000000..16431991d4da
--- /dev/null
+++ b/chromeos/scripts/allconfigs
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+bindir="`pwd`/chromeos/scripts"
+confdir="`pwd`/chromeos/config"
+
+get_flavourconfigs() {
+ for file in `find $confdir`; do
+ if echo $file | egrep -q "config\.flavour\..*[^~]$"; then
+ basename $file | awk -F . '{ print $3 }'
+ fi
+ done
+}
+
+get_arch() {
+ if find . -name config.flavour.$1 | grep -q i386; then
+ echo i386
+ else
+ echo arm
+ fi
+}
+
+for flavour in $(get_flavourconfigs); do
+ echo $flavour $(get_arch $flavour)
+ $bindir/prepareconfig $flavour
+ yes "" | make ARCH=$(get_arch $flavour) oldconfig
+ cp .config .config-$flavour
+done
+
diff --git a/chromeos/scripts/kernelconfig b/chromeos/scripts/kernelconfig
new file mode 100755
index 000000000000..c056c8c6086f
--- /dev/null
+++ b/chromeos/scripts/kernelconfig
@@ -0,0 +1,123 @@
+#!/bin/bash
+
+# Script to merge all configs and run 'make silentoldconfig' on it to wade out bad juju.
+# Then split the configs into distro-commmon and flavour-specific parts
+
+# We have to be in the top level kernel source directory
+if [ ! -f MAINTAINERS ] || [ ! -f Makefile ]; then
+ echo "This does not appear to be the kernel source directory." 1>&2
+ exit 1
+fi
+
+mode=${1:?"Usage: $0 [oldconfig|editconfig]"}
+case "$mode" in
+ oldconfig) ;; # All is good
+ editconfig) ;; # All is good
+ genconfig) ;; # All is good
+ *) echo "$0 called with invalid mode" 1>&2
+ exit 1 ;;
+esac
+kerneldir="`pwd`"
+confdir="$kerneldir/chromeos/config"
+archs="x86_64 i386 armel"
+family='chromeos'
+bindir="`pwd`/chromeos/scripts"
+common_conf="$confdir/config.common.$family"
+tmpdir=`mktemp -d`
+
+if [ "$mode" = "genconfig" ]; then
+ keep=1
+ mode="oldconfig"
+ test -d CONFIGS || mkdir CONFIGS
+fi
+
+test -d build || mkdir build
+
+for arch in $archs; do
+ # Map debian archs to kernel archs
+ case "$arch" in
+ amd64) kernarch="x86_64" ;;
+ lpia) kernarch="x86" ;;
+ sparc) kernarch="sparc64" ;;
+ armel) kernarch="arm" ;;
+ *) kernarch="$arch" ;;
+ esac
+
+ echo ""
+ echo "***************************************"
+ echo "* Processing $arch ($kernarch) ... "
+ archconfdir=$confdir/$arch
+ flavourconfigs=$(cd $archconfdir && ls config.flavour.*[^~])
+
+ # Merge configs
+ # We merge config.common.ubuntu + config.common.<arch> +
+ # config.flavour.<flavour>
+
+ for config in $flavourconfigs; do
+ fullconf="$tmpdir/$arch-$config-full"
+ case $config in
+ *)
+ : >"$fullconf"
+ if [ -f $common_conf ]; then
+ cat $common_conf >> "$fullconf"
+ fi
+ if [ -f $archconfdir/config.common.$arch ]; then
+ cat $archconfdir/config.common.$arch >> "$fullconf"
+ fi
+ cat "$archconfdir/$config" >>"$fullconf"
+ ;;
+ esac
+ done
+
+ for config in $flavourconfigs; do
+ if [ -f $archconfdir/$config ]; then
+ fullconf="$tmpdir/$arch-$config-full"
+ cat "$fullconf" > build/.config
+ # Call oldconfig or menuconfig
+ case "$mode" in
+ oldconfig)
+ # Weed out incorrect config parameters
+ echo "* Run silentoldconfig on $arch/$config ..."
+ make O=`pwd`/build ARCH=$kernarch silentoldconfig ;;
+ editconfig)
+ # Interactively edit config parameters
+ echo " * Run menuconfig on $arch/$config... Press a key."
+ read
+ make O=`pwd`/build ARCH=$kernarch menuconfig ;;
+ *) # Bad!
+ exit 1 ;;
+ esac
+ cat build/.config > $archconfdir/$config
+ if [ "$keep" = "1" ]; then
+ cat build/.config > CONFIGS/$arch-$config
+ fi
+ else
+ echo "!! Config not found $archconfdir/$config..."
+ fi
+ done
+
+ echo "Running splitconfig for $arch"
+ echo
+
+ # Can we make this more robust by avoiding $tmpdir completely?
+ # This approach was used for now because I didn't want to change
+ # splitconfig
+ (cd $archconfdir; rm config.common.$arch; $bindir/splitconfig; \
+ mv config.common config.common.$arch; \
+ cp config.common.$arch $tmpdir)
+done
+
+rm -f $common_conf
+
+# Now run splitconfig on all the config.common.<arch> copied to
+# $tmpdir
+(cd $tmpdir; $bindir/splitconfig)
+(
+ cd $confdir;
+ rm -f *-full
+ grep -v 'is UNMERGABLE' <$tmpdir/config.common >$common_conf
+ for arch in $archs; do
+ grep -v 'is UNMERGABLE' <$tmpdir/config.common.$arch \
+ >$arch/config.common.$arch
+ done
+)
diff --git a/chromeos/scripts/prepareconfig b/chromeos/scripts/prepareconfig
new file mode 100755
index 000000000000..b82cf35919fe
--- /dev/null
+++ b/chromeos/scripts/prepareconfig
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+family=chromeos
+
+flavourconf=$(find ${family} -name config.flavour.$1)
+if [ ! -f "${flavourconf}" ]; then
+ echo "Found no flavour configuration for '$1'." 1>&2
+ exit 1
+fi
+
+outputfile="${2:-.config}"
+
+archconfdir=$(dirname ${flavourconf})
+
+# Generate .config
+cat ${family}/config/config.common.${family} \
+ ${archconfdir}/config.common.* \
+ "${flavourconf}" > "${outputfile}"
diff --git a/chromeos/scripts/splitconfig b/chromeos/scripts/splitconfig
new file mode 100755
index 000000000000..262fa2015c1d
--- /dev/null
+++ b/chromeos/scripts/splitconfig
@@ -0,0 +1,49 @@
+#!/usr/bin/env python
+
+import os
+import re
+import sys
+
+allconfigs = {}
+
+# Parse config files
+for config in os.listdir("."):
+ # Only config.*
+ if not config.startswith("config."):
+ continue
+ # Ignore emacs backups
+ if config.endswith("~"):
+ continue
+ # Nothing that is disabled, or remnant
+ if re.search("\.(default|disabled|stub)$", config):
+ continue
+
+ allconfigs[config] = set()
+
+ for line in open(config):
+ m = re.match("#*\s*CONFIG_(\w+)[\s=](.*)$", line)
+ if not m:
+ continue
+ option, value = m.groups()
+ allconfigs[config].add((option, value))
+
+# Split out common config options
+common = allconfigs.values()[0].copy()
+for config in allconfigs.keys():
+ common &= allconfigs[config]
+for config in allconfigs.keys():
+ allconfigs[config] -= common
+allconfigs["config.common"] = common
+
+# Generate new splitconfigs
+for config in allconfigs.keys():
+ f = open(config, "w")
+ command = os.path.basename(sys.argv[0])
+ print >>f, "#\n# Config options generated by %s\n#" % command
+ for option, value in sorted(list(allconfigs[config])):
+ if value == "is not set":
+ print >>f, "# CONFIG_%s %s" % (option, value)
+ else:
+ print >>f, "CONFIG_%s=%s" % (option, value)
+
+ f.close()
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");
-
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index a13aacea9641..9f9720054c2d 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -98,8 +98,6 @@ next:
*bh = sb_bread(sb, phys);
if (*bh == NULL) {
- fat_msg(sb, KERN_ERR, "Directory bread(block %llu) failed",
- (llu)phys);
/* skip this block */
*pos = (iblock + 1) << sb->s_blocksize_bits;
goto next;
diff --git a/fs/proc/loadavg.c b/fs/proc/loadavg.c
index 1afa4dd4cae2..8d95888b22cd 100644
--- a/fs/proc/loadavg.c
+++ b/fs/proc/loadavg.c
@@ -13,15 +13,17 @@
static int loadavg_proc_show(struct seq_file *m, void *v)
{
unsigned long avnrun[3];
+ unsigned long time_avnrun = avg_nr_running();
get_avenrun(avnrun, FIXED_1/200, 0);
- seq_printf(m, "%lu.%02lu %lu.%02lu %lu.%02lu %ld/%d %d\n",
+ seq_printf(m, "%lu.%02lu %lu.%02lu %lu.%02lu %ld/%d %d %lu.%02lu\n",
LOAD_INT(avnrun[0]), LOAD_FRAC(avnrun[0]),
LOAD_INT(avnrun[1]), LOAD_FRAC(avnrun[1]),
LOAD_INT(avnrun[2]), LOAD_FRAC(avnrun[2]),
nr_running(), nr_threads,
- task_active_pid_ns(current)->last_pid);
+ task_active_pid_ns(current)->last_pid,
+ LOAD_INT(time_avnrun), LOAD_FRAC(time_avnrun));
return 0;
}
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 1d37f42ac294..59b428e5fbc5 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -41,6 +41,26 @@ struct clk;
struct clk *clk_get(struct device *dev, const char *id);
/**
+ * devm_clk_get - lookup and obtain a managed reference to a clock producer.
+ * @dev: device for clock "consumer"
+ * @id: clock comsumer ID
+ *
+ * Returns a struct clk corresponding to the clock producer, or
+ * valid IS_ERR() condition containing errno. The implementation
+ * uses @dev and @id to determine the clock consumer, and thereby
+ * the clock producer. (IOW, @id may be identical strings, but
+ * clk_get may return different clock producers depending on @dev.)
+ *
+ * Drivers must assume that the clock source is not enabled.
+ *
+ * devm_clk_get should not be called from within interrupt context.
+ *
+ * The clock will automatically be freed when the device is unbound
+ * from the bus.
+ */
+struct clk *devm_clk_get(struct device *dev, const char *id);
+
+/**
* clk_enable - inform the system when the clock source should be running.
* @clk: clock source
*
@@ -83,6 +103,18 @@ unsigned long clk_get_rate(struct clk *clk);
*/
void clk_put(struct clk *clk);
+/**
+ * devm_clk_put - "free" a managed clock source
+ * @dev: device used to acuqire the clock
+ * @clk: clock source acquired with devm_clk_get()
+ *
+ * Note: drivers must ensure that all clk_enable calls made on this
+ * clock source are balanced by clk_disable calls prior to calling
+ * this function.
+ *
+ * clk_put should not be called from within interrupt context.
+ */
+void devm_clk_put(struct device *dev, struct clk *clk);
/*
* The remaining APIs are optional for machine class support.
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index c6126b9fb7cf..09b8ea9e194b 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -310,6 +310,7 @@ __ATTR(_name, 0644, show_##_name, store_##_name)
*********************************************************************/
int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu);
int cpufreq_update_policy(unsigned int cpu);
+int cpufreq_set_gov(char *target_gov, unsigned int cpu);
#ifdef CONFIG_CPU_FREQ
/* query the current CPU frequency (in kHz). If zero, cpufreq couldn't detect it */
diff --git a/include/linux/cpuquiet.h b/include/linux/cpuquiet.h
new file mode 100644
index 000000000000..fe5a03727739
--- /dev/null
+++ b/include/linux/cpuquiet.h
@@ -0,0 +1,105 @@
+/*
+ * 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 _LINUX_CPUONLINE_H
+#define _LINUX_CPUONLINE_H
+
+#include <linux/sysfs.h>
+#include <linux/kobject.h>
+
+#define CPUQUIET_NAME_LEN 16
+
+struct cpuquiet_governor {
+ char name[CPUQUIET_NAME_LEN];
+ struct list_head governor_list;
+ int (*start) (void);
+ void (*stop) (void);
+ int (*store_active) (unsigned int cpu, bool active);
+ struct module *owner;
+};
+
+struct cpuquiet_driver {
+ char name[CPUQUIET_NAME_LEN];
+ int (*quiesence_cpu) (unsigned int cpunumber);
+ int (*wake_cpu) (unsigned int cpunumber);
+};
+
+extern int cpuquiet_register_governor(struct cpuquiet_governor *gov);
+extern void cpuquiet_unregister_governor(struct cpuquiet_governor *gov);
+extern int cpuquiet_quiesence_cpu(unsigned int cpunumber);
+extern int cpuquiet_wake_cpu(unsigned int cpunumber);
+extern int cpuquiet_register_driver(struct cpuquiet_driver *drv);
+extern void cpuquiet_unregister_driver(struct cpuquiet_driver *drv);
+extern int cpuquiet_add_group(struct attribute_group *attrs);
+extern void cpuquiet_remove_group(struct attribute_group *attrs);
+int cpuquiet_kobject_init(struct kobject *kobj, struct kobj_type *type,
+ char *name);
+extern unsigned int nr_cluster_ids;
+
+/* Sysfs support */
+struct cpuquiet_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct cpuquiet_attribute *attr, char *buf);
+ ssize_t (*store)(struct cpuquiet_attribute *attr, const char *buf,
+ size_t count);
+ /* Optional. Called after store is called */
+ void (*store_callback)(struct cpuquiet_attribute *attr);
+ void *param;
+};
+
+#define CPQ_ATTRIBUTE(_name, _mode, _type, _callback) \
+ static struct cpuquiet_attribute _name ## _attr = { \
+ .attr = {.name = __stringify(_name), .mode = _mode }, \
+ .show = show_ ## _type ## _attribute, \
+ .store = store_ ## _type ## _attribute, \
+ .store_callback = _callback, \
+ .param = &_name, \
+}
+
+#define CPQ_BASIC_ATTRIBUTE(_name, _mode, _type) \
+ CPQ_ATTRIBUTE(_name, _mode, _type, NULL)
+
+#define CPQ_ATTRIBUTE_CUSTOM(_name, _mode, _show, _store) \
+ static struct cpuquiet_attribute _name ## _attr = { \
+ .attr = {.name = __stringify(_name), .mode = _mode }, \
+ .show = _show, \
+ .store = _store \
+ .store_callback = NULL, \
+ .param = &_name, \
+}
+
+
+extern ssize_t show_int_attribute(struct cpuquiet_attribute *cattr, char *buf);
+extern ssize_t store_int_attribute(struct cpuquiet_attribute *cattr,
+ const char *buf, size_t count);
+extern ssize_t show_bool_attribute(struct cpuquiet_attribute *cattr, char *buf);
+extern ssize_t store_bool_attribute(struct cpuquiet_attribute *cattr,
+ const char *buf, size_t count);
+extern ssize_t store_uint_attribute(struct cpuquiet_attribute *cattr,
+ const char *buf, size_t count);
+extern ssize_t show_uint_attribute(struct cpuquiet_attribute *cattr, char *buf);
+extern ssize_t store_ulong_attribute(struct cpuquiet_attribute *cattr,
+ const char *buf, size_t count);
+extern ssize_t show_ulong_attribute(struct cpuquiet_attribute *cattr,
+ char *buf);
+extern ssize_t cpuquiet_auto_sysfs_show(struct kobject *kobj,
+ struct attribute *attr, char *buf);
+extern ssize_t cpuquiet_auto_sysfs_store(struct kobject *kobj,
+ struct attribute *attr, const char *buf,
+ size_t count);
+#endif
diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h
index bb92f0b13288..4fea7107fee8 100644
--- a/include/linux/i2c/twl.h
+++ b/include/linux/i2c/twl.h
@@ -862,22 +862,6 @@ static inline int twl4030charger_usb_en(int enable) { return 0; }
#define TWL6030_REG_VDAC 45
#define TWL6030_REG_VUSB 46
-/* These are renamed in 6025 but same registers */
-#define TWL6025_REG_LDO2 48
-#define TWL6025_REG_LDO4 49
-#define TWL6025_REG_LDO3 50
-#define TWL6025_REG_LDO5 51
-#define TWL6025_REG_LDO1 52
-#define TWL6025_REG_LDO7 53
-#define TWL6025_REG_LDO6 54
-#define TWL6025_REG_LDOLN 55
-#define TWL6025_REG_LDOUSB 56
-
-/* 6025 DCDC supplies */
-#define TWL6025_REG_SMPS3 57
-#define TWL6025_REG_SMPS4 58
-#define TWL6025_REG_VIO 59
-
/* INTERNAL LDOs */
#define TWL6030_REG_VRTC 47
#define TWL6030_REG_CLK32KG 48
diff --git a/include/linux/lightsensor.h b/include/linux/lightsensor.h
index 7a87853ac064..fc683fd786ac 100644
--- a/include/linux/lightsensor.h
+++ b/include/linux/lightsensor.h
@@ -24,5 +24,6 @@
#define LIGHTSENSOR_IOCTL_GET_ENABLED _IOR(LIGHTSENSOR_IOCTL_MAGIC, 1, int *)
#define LIGHTSENSOR_IOCTL_ENABLE _IOW(LIGHTSENSOR_IOCTL_MAGIC, 2, int *)
+#define LIGHTSENSOR_IOCTL_SET_DELAY _IOW(LIGHTSENSOR_IOCTL_MAGIC, 3, int *)
#endif
diff --git a/include/linux/mfd/palmas.h b/include/linux/mfd/palmas.h
new file mode 100644
index 000000000000..9cbc642d40ad
--- /dev/null
+++ b/include/linux/mfd/palmas.h
@@ -0,0 +1,2620 @@
+/*
+ * TI Palmas
+ *
+ * Copyright 2011 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.
+ *
+ */
+
+#ifndef __LINUX_MFD_PALMAS_H
+#define __LINUX_MFD_PALMAS_H
+
+#include <linux/usb/otg.h>
+#include <linux/leds.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+
+#define PALMAS_NUM_CLIENTS 3
+
+struct palmas_pmic;
+
+struct palmas {
+ struct device *dev;
+
+ struct i2c_client *i2c_clients[PALMAS_NUM_CLIENTS];
+ struct regmap *regmap[PALMAS_NUM_CLIENTS];
+
+ /* Stored chip id */
+ int id;
+
+ /* IRQ Data */
+ int irq;
+ u32 irq_mask;
+ struct mutex irq_lock;
+ struct regmap_irq_chip_data *irq_data;
+
+ /* Child Devices */
+ struct palmas_pmic *pmic;
+
+ /* GPIO MUXing */
+ u8 gpio_muxed;
+ u8 led_muxed;
+ u8 pwm_muxed;
+};
+
+struct palmas_reg_init {
+ /* warm_rest controls the voltage levels after a warm reset
+ *
+ * 0: reload default values from OTP on warm reset
+ * 1: maintain voltage from VSEL on warm reset
+ */
+ int warm_reset;
+
+ /* roof_floor controls whether the regulator uses the i2c style
+ * of DVS or uses the method where a GPIO or other control method is
+ * attached to the NSLEEP/ENABLE1/ENABLE2 pins
+ *
+ * For SMPS
+ *
+ * 0: i2c selection of voltage
+ * 1: pin selection of voltage.
+ *
+ * For LDO unused
+ */
+ int roof_floor;
+
+ /* sleep_mode is the mode loaded to MODE_SLEEP bits as defined in
+ * the data sheet.
+ *
+ * For SMPS
+ *
+ * 0: Off
+ * 1: AUTO
+ * 2: ECO
+ * 3: Forced PWM
+ *
+ * For LDO
+ *
+ * 0: Off
+ * 1: On
+ */
+ int mode_sleep;
+
+ /* tstep is the timestep loaded to the TSTEP register
+ *
+ * For SMPS
+ *
+ * 0: Jump (no slope control)
+ * 1: 10mV/us
+ * 2: 5mV/us
+ * 3: 2.5mV/us
+ *
+ * For LDO unused
+ */
+ int tstep;
+
+ /* voltage_sel is the bitfield loaded onto the SMPSX_VOLTAGE
+ * register. Set this is the default voltage set in OTP needs
+ * to be overridden.
+ */
+ u8 vsel;
+
+};
+
+struct palmas_pmic_platform_data {
+ /* An array of pointers to regulator init data indexed by regulator
+ * ID
+ */
+ struct regulator_init_data **reg_data;
+
+ /* An array of pointers to structures containing sleep mode and DVS
+ * configuration for regulators indexed by ID
+ */
+ struct palmas_reg_init **reg_init;
+
+ /* use LDO6 for vibrator control */
+ int ldo6_vibrator;
+
+
+};
+
+struct palmas_platform_data {
+ int gpio_base;
+
+ /* bit value to be loaded to the POWER_CTRL register */
+ u8 power_ctrl;
+
+ /*
+ * boolean to select if we want to configure muxing here
+ * then the two value to load into the registers if true
+ */
+ int mux_from_pdata;
+ u8 pad1, pad2;
+
+ struct palmas_pmic_platform_data *pmic_pdata;
+};
+
+/* Define the palmas IRQ numbers */
+enum palmas_irqs {
+ /* INT1 registers */
+ PALMAS_CHARG_DET_N_VBUS_OVV_IRQ,
+ PALMAS_PWRON_IRQ,
+ PALMAS_LONG_PRESS_KEY_IRQ,
+ PALMAS_RPWRON_IRQ,
+ PALMAS_PWRDOWN_IRQ,
+ PALMAS_HOTDIE_IRQ,
+ PALMAS_VSYS_MON_IRQ,
+ PALMAS_VBAT_MON_IRQ,
+ /* INT2 registers */
+ PALMAS_RTC_ALARM_IRQ,
+ PALMAS_RTC_TIMER_IRQ,
+ PALMAS_WDT_IRQ,
+ PALMAS_BATREMOVAL_IRQ,
+ PALMAS_RESET_IN_IRQ,
+ PALMAS_FBI_BB_IRQ,
+ PALMAS_SHORT_IRQ,
+ PALMAS_VAC_ACOK_IRQ,
+ /* INT3 registers */
+ PALMAS_GPADC_AUTO_0_IRQ,
+ PALMAS_GPADC_AUTO_1_IRQ,
+ PALMAS_GPADC_EOC_SW_IRQ,
+ PALMAS_GPADC_EOC_RT_IRQ,
+ PALMAS_ID_OTG_IRQ,
+ PALMAS_ID_IRQ,
+ PALMAS_VBUS_OTG_IRQ,
+ PALMAS_VBUS_IRQ,
+ /* INT4 registers */
+ PALMAS_GPIO_0_IRQ,
+ PALMAS_GPIO_1_IRQ,
+ PALMAS_GPIO_2_IRQ,
+ PALMAS_GPIO_3_IRQ,
+ PALMAS_GPIO_4_IRQ,
+ PALMAS_GPIO_5_IRQ,
+ PALMAS_GPIO_6_IRQ,
+ PALMAS_GPIO_7_IRQ,
+ /* Total Number IRQs */
+ PALMAS_NUM_IRQ,
+};
+
+enum palmas_regulators {
+ /* SMPS regulators */
+ PALMAS_REG_SMPS12,
+ PALMAS_REG_SMPS123,
+ PALMAS_REG_SMPS3,
+ PALMAS_REG_SMPS45,
+ PALMAS_REG_SMPS457,
+ PALMAS_REG_SMPS6,
+ PALMAS_REG_SMPS7,
+ PALMAS_REG_SMPS8,
+ PALMAS_REG_SMPS9,
+ PALMAS_REG_SMPS10,
+ /* LDO regulators */
+ PALMAS_REG_LDO1,
+ PALMAS_REG_LDO2,
+ PALMAS_REG_LDO3,
+ PALMAS_REG_LDO4,
+ PALMAS_REG_LDO5,
+ PALMAS_REG_LDO6,
+ PALMAS_REG_LDO7,
+ PALMAS_REG_LDO8,
+ PALMAS_REG_LDO9,
+ PALMAS_REG_LDOLN,
+ PALMAS_REG_LDOUSB,
+ /* Total number of regulators */
+ PALMAS_NUM_REGS,
+};
+
+struct palmas_pmic {
+ struct palmas *palmas;
+ struct device *dev;
+ struct regulator_desc desc[PALMAS_NUM_REGS];
+ struct regulator_dev *rdev[PALMAS_NUM_REGS];
+ struct mutex mutex;
+
+ int smps123;
+ int smps457;
+
+ int range[PALMAS_REG_SMPS10];
+};
+
+/* defines so we can store the mux settings */
+#define PALMAS_GPIO_0_MUXED (1 << 0)
+#define PALMAS_GPIO_1_MUXED (1 << 1)
+#define PALMAS_GPIO_2_MUXED (1 << 2)
+#define PALMAS_GPIO_3_MUXED (1 << 3)
+#define PALMAS_GPIO_4_MUXED (1 << 4)
+#define PALMAS_GPIO_5_MUXED (1 << 5)
+#define PALMAS_GPIO_6_MUXED (1 << 6)
+#define PALMAS_GPIO_7_MUXED (1 << 7)
+
+#define PALMAS_LED1_MUXED (1 << 0)
+#define PALMAS_LED2_MUXED (1 << 1)
+
+#define PALMAS_PWM1_MUXED (1 << 0)
+#define PALMAS_PWM2_MUXED (1 << 1)
+
+/* helper macro to get correct slave number */
+#define PALMAS_BASE_TO_SLAVE(x) ((x >> 8) - 1)
+#define PALMAS_BASE_TO_REG(x, y) ((x & 0xff) + y)
+
+/* Base addresses of IP blocks in Palmas */
+#define PALMAS_SMPS_DVS_BASE 0x20
+#define PALMAS_RTC_BASE 0x100
+#define PALMAS_VALIDITY_BASE 0x118
+#define PALMAS_SMPS_BASE 0x120
+#define PALMAS_LDO_BASE 0x150
+#define PALMAS_DVFS_BASE 0x180
+#define PALMAS_PMU_CONTROL_BASE 0x1A0
+#define PALMAS_RESOURCE_BASE 0x1D4
+#define PALMAS_PU_PD_OD_BASE 0x1F4
+#define PALMAS_LED_BASE 0x200
+#define PALMAS_INTERRUPT_BASE 0x210
+#define PALMAS_USB_OTG_BASE 0x250
+#define PALMAS_VIBRATOR_BASE 0x270
+#define PALMAS_GPIO_BASE 0x280
+#define PALMAS_USB_BASE 0x290
+#define PALMAS_GPADC_BASE 0x2C0
+#define PALMAS_TRIM_GPADC_BASE 0x3CD
+
+/* Registers for function RTC */
+#define PALMAS_SECONDS_REG 0x0
+#define PALMAS_MINUTES_REG 0x1
+#define PALMAS_HOURS_REG 0x2
+#define PALMAS_DAYS_REG 0x3
+#define PALMAS_MONTHS_REG 0x4
+#define PALMAS_YEARS_REG 0x5
+#define PALMAS_WEEKS_REG 0x6
+#define PALMAS_ALARM_SECONDS_REG 0x8
+#define PALMAS_ALARM_MINUTES_REG 0x9
+#define PALMAS_ALARM_HOURS_REG 0xA
+#define PALMAS_ALARM_DAYS_REG 0xB
+#define PALMAS_ALARM_MONTHS_REG 0xC
+#define PALMAS_ALARM_YEARS_REG 0xD
+#define PALMAS_RTC_CTRL_REG 0x10
+#define PALMAS_RTC_STATUS_REG 0x11
+#define PALMAS_RTC_INTERRUPTS_REG 0x12
+#define PALMAS_RTC_COMP_LSB_REG 0x13
+#define PALMAS_RTC_COMP_MSB_REG 0x14
+#define PALMAS_RTC_RES_PROG_REG 0x15
+#define PALMAS_RTC_RESET_STATUS_REG 0x16
+
+/* Bit definitions for SECONDS_REG */
+#define PALMAS_SECONDS_REG_SEC1_MASK 0x70
+#define PALMAS_SECONDS_REG_SEC1_SHIFT 4
+#define PALMAS_SECONDS_REG_SEC0_MASK 0x0f
+#define PALMAS_SECONDS_REG_SEC0_SHIFT 0
+
+/* Bit definitions for MINUTES_REG */
+#define PALMAS_MINUTES_REG_MIN1_MASK 0x70
+#define PALMAS_MINUTES_REG_MIN1_SHIFT 4
+#define PALMAS_MINUTES_REG_MIN0_MASK 0x0f
+#define PALMAS_MINUTES_REG_MIN0_SHIFT 0
+
+/* Bit definitions for HOURS_REG */
+#define PALMAS_HOURS_REG_PM_NAM 0x80
+#define PALMAS_HOURS_REG_PM_NAM_SHIFT 7
+#define PALMAS_HOURS_REG_HOUR1_MASK 0x30
+#define PALMAS_HOURS_REG_HOUR1_SHIFT 4
+#define PALMAS_HOURS_REG_HOUR0_MASK 0x0f
+#define PALMAS_HOURS_REG_HOUR0_SHIFT 0
+
+/* Bit definitions for DAYS_REG */
+#define PALMAS_DAYS_REG_DAY1_MASK 0x30
+#define PALMAS_DAYS_REG_DAY1_SHIFT 4
+#define PALMAS_DAYS_REG_DAY0_MASK 0x0f
+#define PALMAS_DAYS_REG_DAY0_SHIFT 0
+
+/* Bit definitions for MONTHS_REG */
+#define PALMAS_MONTHS_REG_MONTH1 0x10
+#define PALMAS_MONTHS_REG_MONTH1_SHIFT 4
+#define PALMAS_MONTHS_REG_MONTH0_MASK 0x0f
+#define PALMAS_MONTHS_REG_MONTH0_SHIFT 0
+
+/* Bit definitions for YEARS_REG */
+#define PALMAS_YEARS_REG_YEAR1_MASK 0xf0
+#define PALMAS_YEARS_REG_YEAR1_SHIFT 4
+#define PALMAS_YEARS_REG_YEAR0_MASK 0x0f
+#define PALMAS_YEARS_REG_YEAR0_SHIFT 0
+
+/* Bit definitions for WEEKS_REG */
+#define PALMAS_WEEKS_REG_WEEK_MASK 0x07
+#define PALMAS_WEEKS_REG_WEEK_SHIFT 0
+
+/* Bit definitions for ALARM_SECONDS_REG */
+#define PALMAS_ALARM_SECONDS_REG_ALARM_SEC1_MASK 0x70
+#define PALMAS_ALARM_SECONDS_REG_ALARM_SEC1_SHIFT 4
+#define PALMAS_ALARM_SECONDS_REG_ALARM_SEC0_MASK 0x0f
+#define PALMAS_ALARM_SECONDS_REG_ALARM_SEC0_SHIFT 0
+
+/* Bit definitions for ALARM_MINUTES_REG */
+#define PALMAS_ALARM_MINUTES_REG_ALARM_MIN1_MASK 0x70
+#define PALMAS_ALARM_MINUTES_REG_ALARM_MIN1_SHIFT 4
+#define PALMAS_ALARM_MINUTES_REG_ALARM_MIN0_MASK 0x0f
+#define PALMAS_ALARM_MINUTES_REG_ALARM_MIN0_SHIFT 0
+
+/* Bit definitions for ALARM_HOURS_REG */
+#define PALMAS_ALARM_HOURS_REG_ALARM_PM_NAM 0x80
+#define PALMAS_ALARM_HOURS_REG_ALARM_PM_NAM_SHIFT 7
+#define PALMAS_ALARM_HOURS_REG_ALARM_HOUR1_MASK 0x30
+#define PALMAS_ALARM_HOURS_REG_ALARM_HOUR1_SHIFT 4
+#define PALMAS_ALARM_HOURS_REG_ALARM_HOUR0_MASK 0x0f
+#define PALMAS_ALARM_HOURS_REG_ALARM_HOUR0_SHIFT 0
+
+/* Bit definitions for ALARM_DAYS_REG */
+#define PALMAS_ALARM_DAYS_REG_ALARM_DAY1_MASK 0x30
+#define PALMAS_ALARM_DAYS_REG_ALARM_DAY1_SHIFT 4
+#define PALMAS_ALARM_DAYS_REG_ALARM_DAY0_MASK 0x0f
+#define PALMAS_ALARM_DAYS_REG_ALARM_DAY0_SHIFT 0
+
+/* Bit definitions for ALARM_MONTHS_REG */
+#define PALMAS_ALARM_MONTHS_REG_ALARM_MONTH1 0x10
+#define PALMAS_ALARM_MONTHS_REG_ALARM_MONTH1_SHIFT 4
+#define PALMAS_ALARM_MONTHS_REG_ALARM_MONTH0_MASK 0x0f
+#define PALMAS_ALARM_MONTHS_REG_ALARM_MONTH0_SHIFT 0
+
+/* Bit definitions for ALARM_YEARS_REG */
+#define PALMAS_ALARM_YEARS_REG_ALARM_YEAR1_MASK 0xf0
+#define PALMAS_ALARM_YEARS_REG_ALARM_YEAR1_SHIFT 4
+#define PALMAS_ALARM_YEARS_REG_ALARM_YEAR0_MASK 0x0f
+#define PALMAS_ALARM_YEARS_REG_ALARM_YEAR0_SHIFT 0
+
+/* Bit definitions for RTC_CTRL_REG */
+#define PALMAS_RTC_CTRL_REG_RTC_V_OPT 0x80
+#define PALMAS_RTC_CTRL_REG_RTC_V_OPT_SHIFT 7
+#define PALMAS_RTC_CTRL_REG_GET_TIME 0x40
+#define PALMAS_RTC_CTRL_REG_GET_TIME_SHIFT 6
+#define PALMAS_RTC_CTRL_REG_SET_32_COUNTER 0x20
+#define PALMAS_RTC_CTRL_REG_SET_32_COUNTER_SHIFT 5
+#define PALMAS_RTC_CTRL_REG_TEST_MODE 0x10
+#define PALMAS_RTC_CTRL_REG_TEST_MODE_SHIFT 4
+#define PALMAS_RTC_CTRL_REG_MODE_12_24 0x08
+#define PALMAS_RTC_CTRL_REG_MODE_12_24_SHIFT 3
+#define PALMAS_RTC_CTRL_REG_AUTO_COMP 0x04
+#define PALMAS_RTC_CTRL_REG_AUTO_COMP_SHIFT 2
+#define PALMAS_RTC_CTRL_REG_ROUND_30S 0x02
+#define PALMAS_RTC_CTRL_REG_ROUND_30S_SHIFT 1
+#define PALMAS_RTC_CTRL_REG_STOP_RTC 0x01
+#define PALMAS_RTC_CTRL_REG_STOP_RTC_SHIFT 0
+
+/* Bit definitions for RTC_STATUS_REG */
+#define PALMAS_RTC_STATUS_REG_POWER_UP 0x80
+#define PALMAS_RTC_STATUS_REG_POWER_UP_SHIFT 7
+#define PALMAS_RTC_STATUS_REG_ALARM 0x40
+#define PALMAS_RTC_STATUS_REG_ALARM_SHIFT 6
+#define PALMAS_RTC_STATUS_REG_EVENT_1D 0x20
+#define PALMAS_RTC_STATUS_REG_EVENT_1D_SHIFT 5
+#define PALMAS_RTC_STATUS_REG_EVENT_1H 0x10
+#define PALMAS_RTC_STATUS_REG_EVENT_1H_SHIFT 4
+#define PALMAS_RTC_STATUS_REG_EVENT_1M 0x08
+#define PALMAS_RTC_STATUS_REG_EVENT_1M_SHIFT 3
+#define PALMAS_RTC_STATUS_REG_EVENT_1S 0x04
+#define PALMAS_RTC_STATUS_REG_EVENT_1S_SHIFT 2
+#define PALMAS_RTC_STATUS_REG_RUN 0x02
+#define PALMAS_RTC_STATUS_REG_RUN_SHIFT 1
+
+/* Bit definitions for RTC_INTERRUPTS_REG */
+#define PALMAS_RTC_INTERRUPTS_REG_IT_SLEEP_MASK_EN 0x10
+#define PALMAS_RTC_INTERRUPTS_REG_IT_SLEEP_MASK_EN_SHIFT 4
+#define PALMAS_RTC_INTERRUPTS_REG_IT_ALARM 0x08
+#define PALMAS_RTC_INTERRUPTS_REG_IT_ALARM_SHIFT 3
+#define PALMAS_RTC_INTERRUPTS_REG_IT_TIMER 0x04
+#define PALMAS_RTC_INTERRUPTS_REG_IT_TIMER_SHIFT 2
+#define PALMAS_RTC_INTERRUPTS_REG_EVERY_MASK 0x03
+#define PALMAS_RTC_INTERRUPTS_REG_EVERY_SHIFT 0
+
+/* Bit definitions for RTC_COMP_LSB_REG */
+#define PALMAS_RTC_COMP_LSB_REG_RTC_COMP_LSB_MASK 0xff
+#define PALMAS_RTC_COMP_LSB_REG_RTC_COMP_LSB_SHIFT 0
+
+/* Bit definitions for RTC_COMP_MSB_REG */
+#define PALMAS_RTC_COMP_MSB_REG_RTC_COMP_MSB_MASK 0xff
+#define PALMAS_RTC_COMP_MSB_REG_RTC_COMP_MSB_SHIFT 0
+
+/* Bit definitions for RTC_RES_PROG_REG */
+#define PALMAS_RTC_RES_PROG_REG_SW_RES_PROG_MASK 0x3f
+#define PALMAS_RTC_RES_PROG_REG_SW_RES_PROG_SHIFT 0
+
+/* Bit definitions for RTC_RESET_STATUS_REG */
+#define PALMAS_RTC_RESET_STATUS_REG_RESET_STATUS 0x01
+#define PALMAS_RTC_RESET_STATUS_REG_RESET_STATUS_SHIFT 0
+
+/* Registers for function BACKUP */
+#define PALMAS_BACKUP0 0x0
+#define PALMAS_BACKUP1 0x1
+#define PALMAS_BACKUP2 0x2
+#define PALMAS_BACKUP3 0x3
+#define PALMAS_BACKUP4 0x4
+#define PALMAS_BACKUP5 0x5
+#define PALMAS_BACKUP6 0x6
+#define PALMAS_BACKUP7 0x7
+
+/* Bit definitions for BACKUP0 */
+#define PALMAS_BACKUP0_BACKUP_MASK 0xff
+#define PALMAS_BACKUP0_BACKUP_SHIFT 0
+
+/* Bit definitions for BACKUP1 */
+#define PALMAS_BACKUP1_BACKUP_MASK 0xff
+#define PALMAS_BACKUP1_BACKUP_SHIFT 0
+
+/* Bit definitions for BACKUP2 */
+#define PALMAS_BACKUP2_BACKUP_MASK 0xff
+#define PALMAS_BACKUP2_BACKUP_SHIFT 0
+
+/* Bit definitions for BACKUP3 */
+#define PALMAS_BACKUP3_BACKUP_MASK 0xff
+#define PALMAS_BACKUP3_BACKUP_SHIFT 0
+
+/* Bit definitions for BACKUP4 */
+#define PALMAS_BACKUP4_BACKUP_MASK 0xff
+#define PALMAS_BACKUP4_BACKUP_SHIFT 0
+
+/* Bit definitions for BACKUP5 */
+#define PALMAS_BACKUP5_BACKUP_MASK 0xff
+#define PALMAS_BACKUP5_BACKUP_SHIFT 0
+
+/* Bit definitions for BACKUP6 */
+#define PALMAS_BACKUP6_BACKUP_MASK 0xff
+#define PALMAS_BACKUP6_BACKUP_SHIFT 0
+
+/* Bit definitions for BACKUP7 */
+#define PALMAS_BACKUP7_BACKUP_MASK 0xff
+#define PALMAS_BACKUP7_BACKUP_SHIFT 0
+
+/* Registers for function SMPS */
+#define PALMAS_SMPS12_CTRL 0x0
+#define PALMAS_SMPS12_TSTEP 0x1
+#define PALMAS_SMPS12_FORCE 0x2
+#define PALMAS_SMPS12_VOLTAGE 0x3
+#define PALMAS_SMPS3_CTRL 0x4
+#define PALMAS_SMPS3_VOLTAGE 0x7
+#define PALMAS_SMPS45_CTRL 0x8
+#define PALMAS_SMPS45_TSTEP 0x9
+#define PALMAS_SMPS45_FORCE 0xA
+#define PALMAS_SMPS45_VOLTAGE 0xB
+#define PALMAS_SMPS6_CTRL 0xC
+#define PALMAS_SMPS6_TSTEP 0xD
+#define PALMAS_SMPS6_FORCE 0xE
+#define PALMAS_SMPS6_VOLTAGE 0xF
+#define PALMAS_SMPS7_CTRL 0x10
+#define PALMAS_SMPS7_VOLTAGE 0x13
+#define PALMAS_SMPS8_CTRL 0x14
+#define PALMAS_SMPS8_TSTEP 0x15
+#define PALMAS_SMPS8_FORCE 0x16
+#define PALMAS_SMPS8_VOLTAGE 0x17
+#define PALMAS_SMPS9_CTRL 0x18
+#define PALMAS_SMPS9_VOLTAGE 0x1B
+#define PALMAS_SMPS10_CTRL 0x1C
+#define PALMAS_SMPS10_STATUS 0x1F
+#define PALMAS_SMPS_CTRL 0x24
+#define PALMAS_SMPS_PD_CTRL 0x25
+#define PALMAS_SMPS_DITHER_EN 0x26
+#define PALMAS_SMPS_THERMAL_EN 0x27
+#define PALMAS_SMPS_THERMAL_STATUS 0x28
+#define PALMAS_SMPS_SHORT_STATUS 0x29
+#define PALMAS_SMPS_NEGATIVE_CURRENT_LIMIT_EN 0x2A
+#define PALMAS_SMPS_POWERGOOD_MASK1 0x2B
+#define PALMAS_SMPS_POWERGOOD_MASK2 0x2C
+
+/* Bit definitions for SMPS12_CTRL */
+#define PALMAS_SMPS12_CTRL_WR_S 0x80
+#define PALMAS_SMPS12_CTRL_WR_S_SHIFT 7
+#define PALMAS_SMPS12_CTRL_ROOF_FLOOR_EN 0x40
+#define PALMAS_SMPS12_CTRL_ROOF_FLOOR_EN_SHIFT 6
+#define PALMAS_SMPS12_CTRL_STATUS_MASK 0x30
+#define PALMAS_SMPS12_CTRL_STATUS_SHIFT 4
+#define PALMAS_SMPS12_CTRL_MODE_SLEEP_MASK 0x0c
+#define PALMAS_SMPS12_CTRL_MODE_SLEEP_SHIFT 2
+#define PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK 0x03
+#define PALMAS_SMPS12_CTRL_MODE_ACTIVE_SHIFT 0
+
+/* Bit definitions for SMPS12_TSTEP */
+#define PALMAS_SMPS12_TSTEP_TSTEP_MASK 0x03
+#define PALMAS_SMPS12_TSTEP_TSTEP_SHIFT 0
+
+/* Bit definitions for SMPS12_FORCE */
+#define PALMAS_SMPS12_FORCE_CMD 0x80
+#define PALMAS_SMPS12_FORCE_CMD_SHIFT 7
+#define PALMAS_SMPS12_FORCE_VSEL_MASK 0x7f
+#define PALMAS_SMPS12_FORCE_VSEL_SHIFT 0
+
+/* Bit definitions for SMPS12_VOLTAGE */
+#define PALMAS_SMPS12_VOLTAGE_RANGE 0x80
+#define PALMAS_SMPS12_VOLTAGE_RANGE_SHIFT 7
+#define PALMAS_SMPS12_VOLTAGE_VSEL_MASK 0x7f
+#define PALMAS_SMPS12_VOLTAGE_VSEL_SHIFT 0
+
+/* Bit definitions for SMPS3_CTRL */
+#define PALMAS_SMPS3_CTRL_WR_S 0x80
+#define PALMAS_SMPS3_CTRL_WR_S_SHIFT 7
+#define PALMAS_SMPS3_CTRL_STATUS_MASK 0x30
+#define PALMAS_SMPS3_CTRL_STATUS_SHIFT 4
+#define PALMAS_SMPS3_CTRL_MODE_SLEEP_MASK 0x0c
+#define PALMAS_SMPS3_CTRL_MODE_SLEEP_SHIFT 2
+#define PALMAS_SMPS3_CTRL_MODE_ACTIVE_MASK 0x03
+#define PALMAS_SMPS3_CTRL_MODE_ACTIVE_SHIFT 0
+
+/* Bit definitions for SMPS3_VOLTAGE */
+#define PALMAS_SMPS3_VOLTAGE_RANGE 0x80
+#define PALMAS_SMPS3_VOLTAGE_RANGE_SHIFT 7
+#define PALMAS_SMPS3_VOLTAGE_VSEL_MASK 0x7f
+#define PALMAS_SMPS3_VOLTAGE_VSEL_SHIFT 0
+
+/* Bit definitions for SMPS45_CTRL */
+#define PALMAS_SMPS45_CTRL_WR_S 0x80
+#define PALMAS_SMPS45_CTRL_WR_S_SHIFT 7
+#define PALMAS_SMPS45_CTRL_ROOF_FLOOR_EN 0x40
+#define PALMAS_SMPS45_CTRL_ROOF_FLOOR_EN_SHIFT 6
+#define PALMAS_SMPS45_CTRL_STATUS_MASK 0x30
+#define PALMAS_SMPS45_CTRL_STATUS_SHIFT 4
+#define PALMAS_SMPS45_CTRL_MODE_SLEEP_MASK 0x0c
+#define PALMAS_SMPS45_CTRL_MODE_SLEEP_SHIFT 2
+#define PALMAS_SMPS45_CTRL_MODE_ACTIVE_MASK 0x03
+#define PALMAS_SMPS45_CTRL_MODE_ACTIVE_SHIFT 0
+
+/* Bit definitions for SMPS45_TSTEP */
+#define PALMAS_SMPS45_TSTEP_TSTEP_MASK 0x03
+#define PALMAS_SMPS45_TSTEP_TSTEP_SHIFT 0
+
+/* Bit definitions for SMPS45_FORCE */
+#define PALMAS_SMPS45_FORCE_CMD 0x80
+#define PALMAS_SMPS45_FORCE_CMD_SHIFT 7
+#define PALMAS_SMPS45_FORCE_VSEL_MASK 0x7f
+#define PALMAS_SMPS45_FORCE_VSEL_SHIFT 0
+
+/* Bit definitions for SMPS45_VOLTAGE */
+#define PALMAS_SMPS45_VOLTAGE_RANGE 0x80
+#define PALMAS_SMPS45_VOLTAGE_RANGE_SHIFT 7
+#define PALMAS_SMPS45_VOLTAGE_VSEL_MASK 0x7f
+#define PALMAS_SMPS45_VOLTAGE_VSEL_SHIFT 0
+
+/* Bit definitions for SMPS6_CTRL */
+#define PALMAS_SMPS6_CTRL_WR_S 0x80
+#define PALMAS_SMPS6_CTRL_WR_S_SHIFT 7
+#define PALMAS_SMPS6_CTRL_ROOF_FLOOR_EN 0x40
+#define PALMAS_SMPS6_CTRL_ROOF_FLOOR_EN_SHIFT 6
+#define PALMAS_SMPS6_CTRL_STATUS_MASK 0x30
+#define PALMAS_SMPS6_CTRL_STATUS_SHIFT 4
+#define PALMAS_SMPS6_CTRL_MODE_SLEEP_MASK 0x0c
+#define PALMAS_SMPS6_CTRL_MODE_SLEEP_SHIFT 2
+#define PALMAS_SMPS6_CTRL_MODE_ACTIVE_MASK 0x03
+#define PALMAS_SMPS6_CTRL_MODE_ACTIVE_SHIFT 0
+
+/* Bit definitions for SMPS6_TSTEP */
+#define PALMAS_SMPS6_TSTEP_TSTEP_MASK 0x03
+#define PALMAS_SMPS6_TSTEP_TSTEP_SHIFT 0
+
+/* Bit definitions for SMPS6_FORCE */
+#define PALMAS_SMPS6_FORCE_CMD 0x80
+#define PALMAS_SMPS6_FORCE_CMD_SHIFT 7
+#define PALMAS_SMPS6_FORCE_VSEL_MASK 0x7f
+#define PALMAS_SMPS6_FORCE_VSEL_SHIFT 0
+
+/* Bit definitions for SMPS6_VOLTAGE */
+#define PALMAS_SMPS6_VOLTAGE_RANGE 0x80
+#define PALMAS_SMPS6_VOLTAGE_RANGE_SHIFT 7
+#define PALMAS_SMPS6_VOLTAGE_VSEL_MASK 0x7f
+#define PALMAS_SMPS6_VOLTAGE_VSEL_SHIFT 0
+
+/* Bit definitions for SMPS7_CTRL */
+#define PALMAS_SMPS7_CTRL_WR_S 0x80
+#define PALMAS_SMPS7_CTRL_WR_S_SHIFT 7
+#define PALMAS_SMPS7_CTRL_STATUS_MASK 0x30
+#define PALMAS_SMPS7_CTRL_STATUS_SHIFT 4
+#define PALMAS_SMPS7_CTRL_MODE_SLEEP_MASK 0x0c
+#define PALMAS_SMPS7_CTRL_MODE_SLEEP_SHIFT 2
+#define PALMAS_SMPS7_CTRL_MODE_ACTIVE_MASK 0x03
+#define PALMAS_SMPS7_CTRL_MODE_ACTIVE_SHIFT 0
+
+/* Bit definitions for SMPS7_VOLTAGE */
+#define PALMAS_SMPS7_VOLTAGE_RANGE 0x80
+#define PALMAS_SMPS7_VOLTAGE_RANGE_SHIFT 7
+#define PALMAS_SMPS7_VOLTAGE_VSEL_MASK 0x7f
+#define PALMAS_SMPS7_VOLTAGE_VSEL_SHIFT 0
+
+/* Bit definitions for SMPS8_CTRL */
+#define PALMAS_SMPS8_CTRL_WR_S 0x80
+#define PALMAS_SMPS8_CTRL_WR_S_SHIFT 7
+#define PALMAS_SMPS8_CTRL_ROOF_FLOOR_EN 0x40
+#define PALMAS_SMPS8_CTRL_ROOF_FLOOR_EN_SHIFT 6
+#define PALMAS_SMPS8_CTRL_STATUS_MASK 0x30
+#define PALMAS_SMPS8_CTRL_STATUS_SHIFT 4
+#define PALMAS_SMPS8_CTRL_MODE_SLEEP_MASK 0x0c
+#define PALMAS_SMPS8_CTRL_MODE_SLEEP_SHIFT 2
+#define PALMAS_SMPS8_CTRL_MODE_ACTIVE_MASK 0x03
+#define PALMAS_SMPS8_CTRL_MODE_ACTIVE_SHIFT 0
+
+/* Bit definitions for SMPS8_TSTEP */
+#define PALMAS_SMPS8_TSTEP_TSTEP_MASK 0x03
+#define PALMAS_SMPS8_TSTEP_TSTEP_SHIFT 0
+
+/* Bit definitions for SMPS8_FORCE */
+#define PALMAS_SMPS8_FORCE_CMD 0x80
+#define PALMAS_SMPS8_FORCE_CMD_SHIFT 7
+#define PALMAS_SMPS8_FORCE_VSEL_MASK 0x7f
+#define PALMAS_SMPS8_FORCE_VSEL_SHIFT 0
+
+/* Bit definitions for SMPS8_VOLTAGE */
+#define PALMAS_SMPS8_VOLTAGE_RANGE 0x80
+#define PALMAS_SMPS8_VOLTAGE_RANGE_SHIFT 7
+#define PALMAS_SMPS8_VOLTAGE_VSEL_MASK 0x7f
+#define PALMAS_SMPS8_VOLTAGE_VSEL_SHIFT 0
+
+/* Bit definitions for SMPS9_CTRL */
+#define PALMAS_SMPS9_CTRL_WR_S 0x80
+#define PALMAS_SMPS9_CTRL_WR_S_SHIFT 7
+#define PALMAS_SMPS9_CTRL_STATUS_MASK 0x30
+#define PALMAS_SMPS9_CTRL_STATUS_SHIFT 4
+#define PALMAS_SMPS9_CTRL_MODE_SLEEP_MASK 0x0c
+#define PALMAS_SMPS9_CTRL_MODE_SLEEP_SHIFT 2
+#define PALMAS_SMPS9_CTRL_MODE_ACTIVE_MASK 0x03
+#define PALMAS_SMPS9_CTRL_MODE_ACTIVE_SHIFT 0
+
+/* Bit definitions for SMPS9_VOLTAGE */
+#define PALMAS_SMPS9_VOLTAGE_RANGE 0x80
+#define PALMAS_SMPS9_VOLTAGE_RANGE_SHIFT 7
+#define PALMAS_SMPS9_VOLTAGE_VSEL_MASK 0x7f
+#define PALMAS_SMPS9_VOLTAGE_VSEL_SHIFT 0
+
+/* Bit definitions for SMPS10_CTRL */
+#define PALMAS_SMPS10_CTRL_MODE_SLEEP_MASK 0xf0
+#define PALMAS_SMPS10_CTRL_MODE_SLEEP_SHIFT 4
+#define PALMAS_SMPS10_CTRL_MODE_ACTIVE_MASK 0x0f
+#define PALMAS_SMPS10_CTRL_MODE_ACTIVE_SHIFT 0
+
+/* Bit definitions for SMPS10_STATUS */
+#define PALMAS_SMPS10_STATUS_STATUS_MASK 0x0f
+#define PALMAS_SMPS10_STATUS_STATUS_SHIFT 0
+
+/* Bit definitions for SMPS_CTRL */
+#define PALMAS_SMPS_CTRL_SMPS45_SMPS457_EN 0x20
+#define PALMAS_SMPS_CTRL_SMPS45_SMPS457_EN_SHIFT 5
+#define PALMAS_SMPS_CTRL_SMPS12_SMPS123_EN 0x10
+#define PALMAS_SMPS_CTRL_SMPS12_SMPS123_EN_SHIFT 4
+#define PALMAS_SMPS_CTRL_SMPS45_PHASE_CTRL_MASK 0x0c
+#define PALMAS_SMPS_CTRL_SMPS45_PHASE_CTRL_SHIFT 2
+#define PALMAS_SMPS_CTRL_SMPS123_PHASE_CTRL_MASK 0x03
+#define PALMAS_SMPS_CTRL_SMPS123_PHASE_CTRL_SHIFT 0
+
+/* Bit definitions for SMPS_PD_CTRL */
+#define PALMAS_SMPS_PD_CTRL_SMPS9 0x40
+#define PALMAS_SMPS_PD_CTRL_SMPS9_SHIFT 6
+#define PALMAS_SMPS_PD_CTRL_SMPS8 0x20
+#define PALMAS_SMPS_PD_CTRL_SMPS8_SHIFT 5
+#define PALMAS_SMPS_PD_CTRL_SMPS7 0x10
+#define PALMAS_SMPS_PD_CTRL_SMPS7_SHIFT 4
+#define PALMAS_SMPS_PD_CTRL_SMPS6 0x08
+#define PALMAS_SMPS_PD_CTRL_SMPS6_SHIFT 3
+#define PALMAS_SMPS_PD_CTRL_SMPS45 0x04
+#define PALMAS_SMPS_PD_CTRL_SMPS45_SHIFT 2
+#define PALMAS_SMPS_PD_CTRL_SMPS3 0x02
+#define PALMAS_SMPS_PD_CTRL_SMPS3_SHIFT 1
+#define PALMAS_SMPS_PD_CTRL_SMPS12 0x01
+#define PALMAS_SMPS_PD_CTRL_SMPS12_SHIFT 0
+
+/* Bit definitions for SMPS_THERMAL_EN */
+#define PALMAS_SMPS_THERMAL_EN_SMPS9 0x40
+#define PALMAS_SMPS_THERMAL_EN_SMPS9_SHIFT 6
+#define PALMAS_SMPS_THERMAL_EN_SMPS8 0x20
+#define PALMAS_SMPS_THERMAL_EN_SMPS8_SHIFT 5
+#define PALMAS_SMPS_THERMAL_EN_SMPS6 0x08
+#define PALMAS_SMPS_THERMAL_EN_SMPS6_SHIFT 3
+#define PALMAS_SMPS_THERMAL_EN_SMPS457 0x04
+#define PALMAS_SMPS_THERMAL_EN_SMPS457_SHIFT 2
+#define PALMAS_SMPS_THERMAL_EN_SMPS123 0x01
+#define PALMAS_SMPS_THERMAL_EN_SMPS123_SHIFT 0
+
+/* Bit definitions for SMPS_THERMAL_STATUS */
+#define PALMAS_SMPS_THERMAL_STATUS_SMPS9 0x40
+#define PALMAS_SMPS_THERMAL_STATUS_SMPS9_SHIFT 6
+#define PALMAS_SMPS_THERMAL_STATUS_SMPS8 0x20
+#define PALMAS_SMPS_THERMAL_STATUS_SMPS8_SHIFT 5
+#define PALMAS_SMPS_THERMAL_STATUS_SMPS6 0x08
+#define PALMAS_SMPS_THERMAL_STATUS_SMPS6_SHIFT 3
+#define PALMAS_SMPS_THERMAL_STATUS_SMPS457 0x04
+#define PALMAS_SMPS_THERMAL_STATUS_SMPS457_SHIFT 2
+#define PALMAS_SMPS_THERMAL_STATUS_SMPS123 0x01
+#define PALMAS_SMPS_THERMAL_STATUS_SMPS123_SHIFT 0
+
+/* Bit definitions for SMPS_SHORT_STATUS */
+#define PALMAS_SMPS_SHORT_STATUS_SMPS10 0x80
+#define PALMAS_SMPS_SHORT_STATUS_SMPS10_SHIFT 7
+#define PALMAS_SMPS_SHORT_STATUS_SMPS9 0x40
+#define PALMAS_SMPS_SHORT_STATUS_SMPS9_SHIFT 6
+#define PALMAS_SMPS_SHORT_STATUS_SMPS8 0x20
+#define PALMAS_SMPS_SHORT_STATUS_SMPS8_SHIFT 5
+#define PALMAS_SMPS_SHORT_STATUS_SMPS7 0x10
+#define PALMAS_SMPS_SHORT_STATUS_SMPS7_SHIFT 4
+#define PALMAS_SMPS_SHORT_STATUS_SMPS6 0x08
+#define PALMAS_SMPS_SHORT_STATUS_SMPS6_SHIFT 3
+#define PALMAS_SMPS_SHORT_STATUS_SMPS45 0x04
+#define PALMAS_SMPS_SHORT_STATUS_SMPS45_SHIFT 2
+#define PALMAS_SMPS_SHORT_STATUS_SMPS3 0x02
+#define PALMAS_SMPS_SHORT_STATUS_SMPS3_SHIFT 1
+#define PALMAS_SMPS_SHORT_STATUS_SMPS12 0x01
+#define PALMAS_SMPS_SHORT_STATUS_SMPS12_SHIFT 0
+
+/* Bit definitions for SMPS_NEGATIVE_CURRENT_LIMIT_EN */
+#define PALMAS_SMPS_NEGATIVE_CURRENT_LIMIT_EN_SMPS9 0x40
+#define PALMAS_SMPS_NEGATIVE_CURRENT_LIMIT_EN_SMPS9_SHIFT 6
+#define PALMAS_SMPS_NEGATIVE_CURRENT_LIMIT_EN_SMPS8 0x20
+#define PALMAS_SMPS_NEGATIVE_CURRENT_LIMIT_EN_SMPS8_SHIFT 5
+#define PALMAS_SMPS_NEGATIVE_CURRENT_LIMIT_EN_SMPS7 0x10
+#define PALMAS_SMPS_NEGATIVE_CURRENT_LIMIT_EN_SMPS7_SHIFT 4
+#define PALMAS_SMPS_NEGATIVE_CURRENT_LIMIT_EN_SMPS6 0x08
+#define PALMAS_SMPS_NEGATIVE_CURRENT_LIMIT_EN_SMPS6_SHIFT 3
+#define PALMAS_SMPS_NEGATIVE_CURRENT_LIMIT_EN_SMPS45 0x04
+#define PALMAS_SMPS_NEGATIVE_CURRENT_LIMIT_EN_SMPS45_SHIFT 2
+#define PALMAS_SMPS_NEGATIVE_CURRENT_LIMIT_EN_SMPS3 0x02
+#define PALMAS_SMPS_NEGATIVE_CURRENT_LIMIT_EN_SMPS3_SHIFT 1
+#define PALMAS_SMPS_NEGATIVE_CURRENT_LIMIT_EN_SMPS12 0x01
+#define PALMAS_SMPS_NEGATIVE_CURRENT_LIMIT_EN_SMPS12_SHIFT 0
+
+/* Bit definitions for SMPS_POWERGOOD_MASK1 */
+#define PALMAS_SMPS_POWERGOOD_MASK1_SMPS10 0x80
+#define PALMAS_SMPS_POWERGOOD_MASK1_SMPS10_SHIFT 7
+#define PALMAS_SMPS_POWERGOOD_MASK1_SMPS9 0x40
+#define PALMAS_SMPS_POWERGOOD_MASK1_SMPS9_SHIFT 6
+#define PALMAS_SMPS_POWERGOOD_MASK1_SMPS8 0x20
+#define PALMAS_SMPS_POWERGOOD_MASK1_SMPS8_SHIFT 5
+#define PALMAS_SMPS_POWERGOOD_MASK1_SMPS7 0x10
+#define PALMAS_SMPS_POWERGOOD_MASK1_SMPS7_SHIFT 4
+#define PALMAS_SMPS_POWERGOOD_MASK1_SMPS6 0x08
+#define PALMAS_SMPS_POWERGOOD_MASK1_SMPS6_SHIFT 3
+#define PALMAS_SMPS_POWERGOOD_MASK1_SMPS45 0x04
+#define PALMAS_SMPS_POWERGOOD_MASK1_SMPS45_SHIFT 2
+#define PALMAS_SMPS_POWERGOOD_MASK1_SMPS3 0x02
+#define PALMAS_SMPS_POWERGOOD_MASK1_SMPS3_SHIFT 1
+#define PALMAS_SMPS_POWERGOOD_MASK1_SMPS12 0x01
+#define PALMAS_SMPS_POWERGOOD_MASK1_SMPS12_SHIFT 0
+
+/* Bit definitions for SMPS_POWERGOOD_MASK2 */
+#define PALMAS_SMPS_POWERGOOD_MASK2_POWERGOOD_TYPE_SELECT 0x80
+#define PALMAS_SMPS_POWERGOOD_MASK2_POWERGOOD_TYPE_SELECT_SHIFT 7
+#define PALMAS_SMPS_POWERGOOD_MASK2_GPIO_7 0x04
+#define PALMAS_SMPS_POWERGOOD_MASK2_GPIO_7_SHIFT 2
+#define PALMAS_SMPS_POWERGOOD_MASK2_VBUS 0x02
+#define PALMAS_SMPS_POWERGOOD_MASK2_VBUS_SHIFT 1
+#define PALMAS_SMPS_POWERGOOD_MASK2_ACOK 0x01
+#define PALMAS_SMPS_POWERGOOD_MASK2_ACOK_SHIFT 0
+
+/* Registers for function LDO */
+#define PALMAS_LDO1_CTRL 0x0
+#define PALMAS_LDO1_VOLTAGE 0x1
+#define PALMAS_LDO2_CTRL 0x2
+#define PALMAS_LDO2_VOLTAGE 0x3
+#define PALMAS_LDO3_CTRL 0x4
+#define PALMAS_LDO3_VOLTAGE 0x5
+#define PALMAS_LDO4_CTRL 0x6
+#define PALMAS_LDO4_VOLTAGE 0x7
+#define PALMAS_LDO5_CTRL 0x8
+#define PALMAS_LDO5_VOLTAGE 0x9
+#define PALMAS_LDO6_CTRL 0xA
+#define PALMAS_LDO6_VOLTAGE 0xB
+#define PALMAS_LDO7_CTRL 0xC
+#define PALMAS_LDO7_VOLTAGE 0xD
+#define PALMAS_LDO8_CTRL 0xE
+#define PALMAS_LDO8_VOLTAGE 0xF
+#define PALMAS_LDO9_CTRL 0x10
+#define PALMAS_LDO9_VOLTAGE 0x11
+#define PALMAS_LDOLN_CTRL 0x12
+#define PALMAS_LDOLN_VOLTAGE 0x13
+#define PALMAS_LDOUSB_CTRL 0x14
+#define PALMAS_LDOUSB_VOLTAGE 0x15
+#define PALMAS_LDO_CTRL 0x1A
+#define PALMAS_LDO_PD_CTRL1 0x1B
+#define PALMAS_LDO_PD_CTRL2 0x1C
+#define PALMAS_LDO_SHORT_STATUS1 0x1D
+#define PALMAS_LDO_SHORT_STATUS2 0x1E
+
+/* Bit definitions for LDO1_CTRL */
+#define PALMAS_LDO1_CTRL_WR_S 0x80
+#define PALMAS_LDO1_CTRL_WR_S_SHIFT 7
+#define PALMAS_LDO1_CTRL_STATUS 0x10
+#define PALMAS_LDO1_CTRL_STATUS_SHIFT 4
+#define PALMAS_LDO1_CTRL_MODE_SLEEP 0x04
+#define PALMAS_LDO1_CTRL_MODE_SLEEP_SHIFT 2
+#define PALMAS_LDO1_CTRL_MODE_ACTIVE 0x01
+#define PALMAS_LDO1_CTRL_MODE_ACTIVE_SHIFT 0
+
+/* Bit definitions for LDO1_VOLTAGE */
+#define PALMAS_LDO1_VOLTAGE_VSEL_MASK 0x3f
+#define PALMAS_LDO1_VOLTAGE_VSEL_SHIFT 0
+
+/* Bit definitions for LDO2_CTRL */
+#define PALMAS_LDO2_CTRL_WR_S 0x80
+#define PALMAS_LDO2_CTRL_WR_S_SHIFT 7
+#define PALMAS_LDO2_CTRL_STATUS 0x10
+#define PALMAS_LDO2_CTRL_STATUS_SHIFT 4
+#define PALMAS_LDO2_CTRL_MODE_SLEEP 0x04
+#define PALMAS_LDO2_CTRL_MODE_SLEEP_SHIFT 2
+#define PALMAS_LDO2_CTRL_MODE_ACTIVE 0x01
+#define PALMAS_LDO2_CTRL_MODE_ACTIVE_SHIFT 0
+
+/* Bit definitions for LDO2_VOLTAGE */
+#define PALMAS_LDO2_VOLTAGE_VSEL_MASK 0x3f
+#define PALMAS_LDO2_VOLTAGE_VSEL_SHIFT 0
+
+/* Bit definitions for LDO3_CTRL */
+#define PALMAS_LDO3_CTRL_WR_S 0x80
+#define PALMAS_LDO3_CTRL_WR_S_SHIFT 7
+#define PALMAS_LDO3_CTRL_STATUS 0x10
+#define PALMAS_LDO3_CTRL_STATUS_SHIFT 4
+#define PALMAS_LDO3_CTRL_MODE_SLEEP 0x04
+#define PALMAS_LDO3_CTRL_MODE_SLEEP_SHIFT 2
+#define PALMAS_LDO3_CTRL_MODE_ACTIVE 0x01
+#define PALMAS_LDO3_CTRL_MODE_ACTIVE_SHIFT 0
+
+/* Bit definitions for LDO3_VOLTAGE */
+#define PALMAS_LDO3_VOLTAGE_VSEL_MASK 0x3f
+#define PALMAS_LDO3_VOLTAGE_VSEL_SHIFT 0
+
+/* Bit definitions for LDO4_CTRL */
+#define PALMAS_LDO4_CTRL_WR_S 0x80
+#define PALMAS_LDO4_CTRL_WR_S_SHIFT 7
+#define PALMAS_LDO4_CTRL_STATUS 0x10
+#define PALMAS_LDO4_CTRL_STATUS_SHIFT 4
+#define PALMAS_LDO4_CTRL_MODE_SLEEP 0x04
+#define PALMAS_LDO4_CTRL_MODE_SLEEP_SHIFT 2
+#define PALMAS_LDO4_CTRL_MODE_ACTIVE 0x01
+#define PALMAS_LDO4_CTRL_MODE_ACTIVE_SHIFT 0
+
+/* Bit definitions for LDO4_VOLTAGE */
+#define PALMAS_LDO4_VOLTAGE_VSEL_MASK 0x3f
+#define PALMAS_LDO4_VOLTAGE_VSEL_SHIFT 0
+
+/* Bit definitions for LDO5_CTRL */
+#define PALMAS_LDO5_CTRL_WR_S 0x80
+#define PALMAS_LDO5_CTRL_WR_S_SHIFT 7
+#define PALMAS_LDO5_CTRL_STATUS 0x10
+#define PALMAS_LDO5_CTRL_STATUS_SHIFT 4
+#define PALMAS_LDO5_CTRL_MODE_SLEEP 0x04
+#define PALMAS_LDO5_CTRL_MODE_SLEEP_SHIFT 2
+#define PALMAS_LDO5_CTRL_MODE_ACTIVE 0x01
+#define PALMAS_LDO5_CTRL_MODE_ACTIVE_SHIFT 0
+
+/* Bit definitions for LDO5_VOLTAGE */
+#define PALMAS_LDO5_VOLTAGE_VSEL_MASK 0x3f
+#define PALMAS_LDO5_VOLTAGE_VSEL_SHIFT 0
+
+/* Bit definitions for LDO6_CTRL */
+#define PALMAS_LDO6_CTRL_WR_S 0x80
+#define PALMAS_LDO6_CTRL_WR_S_SHIFT 7
+#define PALMAS_LDO6_CTRL_LDO_VIB_EN 0x40
+#define PALMAS_LDO6_CTRL_LDO_VIB_EN_SHIFT 6
+#define PALMAS_LDO6_CTRL_STATUS 0x10
+#define PALMAS_LDO6_CTRL_STATUS_SHIFT 4
+#define PALMAS_LDO6_CTRL_MODE_SLEEP 0x04
+#define PALMAS_LDO6_CTRL_MODE_SLEEP_SHIFT 2
+#define PALMAS_LDO6_CTRL_MODE_ACTIVE 0x01
+#define PALMAS_LDO6_CTRL_MODE_ACTIVE_SHIFT 0
+
+/* Bit definitions for LDO6_VOLTAGE */
+#define PALMAS_LDO6_VOLTAGE_VSEL_MASK 0x3f
+#define PALMAS_LDO6_VOLTAGE_VSEL_SHIFT 0
+
+/* Bit definitions for LDO7_CTRL */
+#define PALMAS_LDO7_CTRL_WR_S 0x80
+#define PALMAS_LDO7_CTRL_WR_S_SHIFT 7
+#define PALMAS_LDO7_CTRL_STATUS 0x10
+#define PALMAS_LDO7_CTRL_STATUS_SHIFT 4
+#define PALMAS_LDO7_CTRL_MODE_SLEEP 0x04
+#define PALMAS_LDO7_CTRL_MODE_SLEEP_SHIFT 2
+#define PALMAS_LDO7_CTRL_MODE_ACTIVE 0x01
+#define PALMAS_LDO7_CTRL_MODE_ACTIVE_SHIFT 0
+
+/* Bit definitions for LDO7_VOLTAGE */
+#define PALMAS_LDO7_VOLTAGE_VSEL_MASK 0x3f
+#define PALMAS_LDO7_VOLTAGE_VSEL_SHIFT 0
+
+/* Bit definitions for LDO8_CTRL */
+#define PALMAS_LDO8_CTRL_WR_S 0x80
+#define PALMAS_LDO8_CTRL_WR_S_SHIFT 7
+#define PALMAS_LDO8_CTRL_LDO_TRACKING_EN 0x40
+#define PALMAS_LDO8_CTRL_LDO_TRACKING_EN_SHIFT 6
+#define PALMAS_LDO8_CTRL_STATUS 0x10
+#define PALMAS_LDO8_CTRL_STATUS_SHIFT 4
+#define PALMAS_LDO8_CTRL_MODE_SLEEP 0x04
+#define PALMAS_LDO8_CTRL_MODE_SLEEP_SHIFT 2
+#define PALMAS_LDO8_CTRL_MODE_ACTIVE 0x01
+#define PALMAS_LDO8_CTRL_MODE_ACTIVE_SHIFT 0
+
+/* Bit definitions for LDO8_VOLTAGE */
+#define PALMAS_LDO8_VOLTAGE_VSEL_MASK 0x3f
+#define PALMAS_LDO8_VOLTAGE_VSEL_SHIFT 0
+
+/* Bit definitions for LDO9_CTRL */
+#define PALMAS_LDO9_CTRL_WR_S 0x80
+#define PALMAS_LDO9_CTRL_WR_S_SHIFT 7
+#define PALMAS_LDO9_CTRL_LDO_BYPASS_EN 0x40
+#define PALMAS_LDO9_CTRL_LDO_BYPASS_EN_SHIFT 6
+#define PALMAS_LDO9_CTRL_STATUS 0x10
+#define PALMAS_LDO9_CTRL_STATUS_SHIFT 4
+#define PALMAS_LDO9_CTRL_MODE_SLEEP 0x04
+#define PALMAS_LDO9_CTRL_MODE_SLEEP_SHIFT 2
+#define PALMAS_LDO9_CTRL_MODE_ACTIVE 0x01
+#define PALMAS_LDO9_CTRL_MODE_ACTIVE_SHIFT 0
+
+/* Bit definitions for LDO9_VOLTAGE */
+#define PALMAS_LDO9_VOLTAGE_VSEL_MASK 0x3f
+#define PALMAS_LDO9_VOLTAGE_VSEL_SHIFT 0
+
+/* Bit definitions for LDOLN_CTRL */
+#define PALMAS_LDOLN_CTRL_WR_S 0x80
+#define PALMAS_LDOLN_CTRL_WR_S_SHIFT 7
+#define PALMAS_LDOLN_CTRL_STATUS 0x10
+#define PALMAS_LDOLN_CTRL_STATUS_SHIFT 4
+#define PALMAS_LDOLN_CTRL_MODE_SLEEP 0x04
+#define PALMAS_LDOLN_CTRL_MODE_SLEEP_SHIFT 2
+#define PALMAS_LDOLN_CTRL_MODE_ACTIVE 0x01
+#define PALMAS_LDOLN_CTRL_MODE_ACTIVE_SHIFT 0
+
+/* Bit definitions for LDOLN_VOLTAGE */
+#define PALMAS_LDOLN_VOLTAGE_VSEL_MASK 0x3f
+#define PALMAS_LDOLN_VOLTAGE_VSEL_SHIFT 0
+
+/* Bit definitions for LDOUSB_CTRL */
+#define PALMAS_LDOUSB_CTRL_WR_S 0x80
+#define PALMAS_LDOUSB_CTRL_WR_S_SHIFT 7
+#define PALMAS_LDOUSB_CTRL_STATUS 0x10
+#define PALMAS_LDOUSB_CTRL_STATUS_SHIFT 4
+#define PALMAS_LDOUSB_CTRL_MODE_SLEEP 0x04
+#define PALMAS_LDOUSB_CTRL_MODE_SLEEP_SHIFT 2
+#define PALMAS_LDOUSB_CTRL_MODE_ACTIVE 0x01
+#define PALMAS_LDOUSB_CTRL_MODE_ACTIVE_SHIFT 0
+
+/* Bit definitions for LDOUSB_VOLTAGE */
+#define PALMAS_LDOUSB_VOLTAGE_VSEL_MASK 0x3f
+#define PALMAS_LDOUSB_VOLTAGE_VSEL_SHIFT 0
+
+/* Bit definitions for LDO_CTRL */
+#define PALMAS_LDO_CTRL_LDOUSB_ON_VBUS_VSYS 0x01
+#define PALMAS_LDO_CTRL_LDOUSB_ON_VBUS_VSYS_SHIFT 0
+
+/* Bit definitions for LDO_PD_CTRL1 */
+#define PALMAS_LDO_PD_CTRL1_LDO8 0x80
+#define PALMAS_LDO_PD_CTRL1_LDO8_SHIFT 7
+#define PALMAS_LDO_PD_CTRL1_LDO7 0x40
+#define PALMAS_LDO_PD_CTRL1_LDO7_SHIFT 6
+#define PALMAS_LDO_PD_CTRL1_LDO6 0x20
+#define PALMAS_LDO_PD_CTRL1_LDO6_SHIFT 5
+#define PALMAS_LDO_PD_CTRL1_LDO5 0x10
+#define PALMAS_LDO_PD_CTRL1_LDO5_SHIFT 4
+#define PALMAS_LDO_PD_CTRL1_LDO4 0x08
+#define PALMAS_LDO_PD_CTRL1_LDO4_SHIFT 3
+#define PALMAS_LDO_PD_CTRL1_LDO3 0x04
+#define PALMAS_LDO_PD_CTRL1_LDO3_SHIFT 2
+#define PALMAS_LDO_PD_CTRL1_LDO2 0x02
+#define PALMAS_LDO_PD_CTRL1_LDO2_SHIFT 1
+#define PALMAS_LDO_PD_CTRL1_LDO1 0x01
+#define PALMAS_LDO_PD_CTRL1_LDO1_SHIFT 0
+
+/* Bit definitions for LDO_PD_CTRL2 */
+#define PALMAS_LDO_PD_CTRL2_LDOUSB 0x04
+#define PALMAS_LDO_PD_CTRL2_LDOUSB_SHIFT 2
+#define PALMAS_LDO_PD_CTRL2_LDOLN 0x02
+#define PALMAS_LDO_PD_CTRL2_LDOLN_SHIFT 1
+#define PALMAS_LDO_PD_CTRL2_LDO9 0x01
+#define PALMAS_LDO_PD_CTRL2_LDO9_SHIFT 0
+
+/* Bit definitions for LDO_SHORT_STATUS1 */
+#define PALMAS_LDO_SHORT_STATUS1_LDO8 0x80
+#define PALMAS_LDO_SHORT_STATUS1_LDO8_SHIFT 7
+#define PALMAS_LDO_SHORT_STATUS1_LDO7 0x40
+#define PALMAS_LDO_SHORT_STATUS1_LDO7_SHIFT 6
+#define PALMAS_LDO_SHORT_STATUS1_LDO6 0x20
+#define PALMAS_LDO_SHORT_STATUS1_LDO6_SHIFT 5
+#define PALMAS_LDO_SHORT_STATUS1_LDO5 0x10
+#define PALMAS_LDO_SHORT_STATUS1_LDO5_SHIFT 4
+#define PALMAS_LDO_SHORT_STATUS1_LDO4 0x08
+#define PALMAS_LDO_SHORT_STATUS1_LDO4_SHIFT 3
+#define PALMAS_LDO_SHORT_STATUS1_LDO3 0x04
+#define PALMAS_LDO_SHORT_STATUS1_LDO3_SHIFT 2
+#define PALMAS_LDO_SHORT_STATUS1_LDO2 0x02
+#define PALMAS_LDO_SHORT_STATUS1_LDO2_SHIFT 1
+#define PALMAS_LDO_SHORT_STATUS1_LDO1 0x01
+#define PALMAS_LDO_SHORT_STATUS1_LDO1_SHIFT 0
+
+/* Bit definitions for LDO_SHORT_STATUS2 */
+#define PALMAS_LDO_SHORT_STATUS2_LDOVANA 0x08
+#define PALMAS_LDO_SHORT_STATUS2_LDOVANA_SHIFT 3
+#define PALMAS_LDO_SHORT_STATUS2_LDOUSB 0x04
+#define PALMAS_LDO_SHORT_STATUS2_LDOUSB_SHIFT 2
+#define PALMAS_LDO_SHORT_STATUS2_LDOLN 0x02
+#define PALMAS_LDO_SHORT_STATUS2_LDOLN_SHIFT 1
+#define PALMAS_LDO_SHORT_STATUS2_LDO9 0x01
+#define PALMAS_LDO_SHORT_STATUS2_LDO9_SHIFT 0
+
+/* Registers for function PMU_CONTROL */
+#define PALMAS_DEV_CTRL 0x0
+#define PALMAS_POWER_CTRL 0x1
+#define PALMAS_VSYS_LO 0x2
+#define PALMAS_VSYS_MON 0x3
+#define PALMAS_VBAT_MON 0x4
+#define PALMAS_WATCHDOG 0x5
+#define PALMAS_BOOT_STATUS 0x6
+#define PALMAS_BATTERY_BOUNCE 0x7
+#define PALMAS_BACKUP_BATTERY_CTRL 0x8
+#define PALMAS_LONG_PRESS_KEY 0x9
+#define PALMAS_OSC_THERM_CTRL 0xA
+#define PALMAS_BATDEBOUNCING 0xB
+#define PALMAS_SWOFF_HWRST 0xF
+#define PALMAS_SWOFF_COLDRST 0x10
+#define PALMAS_SWOFF_STATUS 0x11
+#define PALMAS_PMU_CONFIG 0x12
+#define PALMAS_SPARE 0x14
+#define PALMAS_PMU_SECONDARY_INT 0x15
+#define PALMAS_SW_REVISION 0x17
+#define PALMAS_EXT_CHRG_CTRL 0x18
+#define PALMAS_PMU_SECONDARY_INT2 0x19
+
+/* Bit definitions for DEV_CTRL */
+#define PALMAS_DEV_CTRL_DEV_STATUS_MASK 0x0c
+#define PALMAS_DEV_CTRL_DEV_STATUS_SHIFT 2
+#define PALMAS_DEV_CTRL_SW_RST 0x02
+#define PALMAS_DEV_CTRL_SW_RST_SHIFT 1
+#define PALMAS_DEV_CTRL_DEV_ON 0x01
+#define PALMAS_DEV_CTRL_DEV_ON_SHIFT 0
+
+/* Bit definitions for POWER_CTRL */
+#define PALMAS_POWER_CTRL_ENABLE2_MASK 0x04
+#define PALMAS_POWER_CTRL_ENABLE2_MASK_SHIFT 2
+#define PALMAS_POWER_CTRL_ENABLE1_MASK 0x02
+#define PALMAS_POWER_CTRL_ENABLE1_MASK_SHIFT 1
+#define PALMAS_POWER_CTRL_NSLEEP_MASK 0x01
+#define PALMAS_POWER_CTRL_NSLEEP_MASK_SHIFT 0
+
+/* Bit definitions for VSYS_LO */
+#define PALMAS_VSYS_LO_THRESHOLD_MASK 0x1f
+#define PALMAS_VSYS_LO_THRESHOLD_SHIFT 0
+
+/* Bit definitions for VSYS_MON */
+#define PALMAS_VSYS_MON_ENABLE 0x80
+#define PALMAS_VSYS_MON_ENABLE_SHIFT 7
+#define PALMAS_VSYS_MON_THRESHOLD_MASK 0x3f
+#define PALMAS_VSYS_MON_THRESHOLD_SHIFT 0
+
+/* Bit definitions for VBAT_MON */
+#define PALMAS_VBAT_MON_ENABLE 0x80
+#define PALMAS_VBAT_MON_ENABLE_SHIFT 7
+#define PALMAS_VBAT_MON_THRESHOLD_MASK 0x3f
+#define PALMAS_VBAT_MON_THRESHOLD_SHIFT 0
+
+/* Bit definitions for WATCHDOG */
+#define PALMAS_WATCHDOG_LOCK 0x20
+#define PALMAS_WATCHDOG_LOCK_SHIFT 5
+#define PALMAS_WATCHDOG_ENABLE 0x10
+#define PALMAS_WATCHDOG_ENABLE_SHIFT 4
+#define PALMAS_WATCHDOG_MODE 0x08
+#define PALMAS_WATCHDOG_MODE_SHIFT 3
+#define PALMAS_WATCHDOG_TIMER_MASK 0x07
+#define PALMAS_WATCHDOG_TIMER_SHIFT 0
+
+/* Bit definitions for BOOT_STATUS */
+#define PALMAS_BOOT_STATUS_BOOT1 0x02
+#define PALMAS_BOOT_STATUS_BOOT1_SHIFT 1
+#define PALMAS_BOOT_STATUS_BOOT0 0x01
+#define PALMAS_BOOT_STATUS_BOOT0_SHIFT 0
+
+/* Bit definitions for BATTERY_BOUNCE */
+#define PALMAS_BATTERY_BOUNCE_BB_DELAY_MASK 0x3f
+#define PALMAS_BATTERY_BOUNCE_BB_DELAY_SHIFT 0
+
+/* Bit definitions for BACKUP_BATTERY_CTRL */
+#define PALMAS_BACKUP_BATTERY_CTRL_VRTC_18_15 0x80
+#define PALMAS_BACKUP_BATTERY_CTRL_VRTC_18_15_SHIFT 7
+#define PALMAS_BACKUP_BATTERY_CTRL_VRTC_EN_SLP 0x40
+#define PALMAS_BACKUP_BATTERY_CTRL_VRTC_EN_SLP_SHIFT 6
+#define PALMAS_BACKUP_BATTERY_CTRL_VRTC_EN_OFF 0x20
+#define PALMAS_BACKUP_BATTERY_CTRL_VRTC_EN_OFF_SHIFT 5
+#define PALMAS_BACKUP_BATTERY_CTRL_VRTC_PWEN 0x10
+#define PALMAS_BACKUP_BATTERY_CTRL_VRTC_PWEN_SHIFT 4
+#define PALMAS_BACKUP_BATTERY_CTRL_BBS_BBC_LOW_ICHRG 0x08
+#define PALMAS_BACKUP_BATTERY_CTRL_BBS_BBC_LOW_ICHRG_SHIFT 3
+#define PALMAS_BACKUP_BATTERY_CTRL_BB_SEL_MASK 0x06
+#define PALMAS_BACKUP_BATTERY_CTRL_BB_SEL_SHIFT 1
+#define PALMAS_BACKUP_BATTERY_CTRL_BB_CHG_EN 0x01
+#define PALMAS_BACKUP_BATTERY_CTRL_BB_CHG_EN_SHIFT 0
+
+/* Bit definitions for LONG_PRESS_KEY */
+#define PALMAS_LONG_PRESS_KEY_LPK_LOCK 0x80
+#define PALMAS_LONG_PRESS_KEY_LPK_LOCK_SHIFT 7
+#define PALMAS_LONG_PRESS_KEY_LPK_INT_CLR 0x10
+#define PALMAS_LONG_PRESS_KEY_LPK_INT_CLR_SHIFT 4
+#define PALMAS_LONG_PRESS_KEY_LPK_TIME_MASK 0x0c
+#define PALMAS_LONG_PRESS_KEY_LPK_TIME_SHIFT 2
+#define PALMAS_LONG_PRESS_KEY_PWRON_DEBOUNCE_MASK 0x03
+#define PALMAS_LONG_PRESS_KEY_PWRON_DEBOUNCE_SHIFT 0
+
+/* Bit definitions for OSC_THERM_CTRL */
+#define PALMAS_OSC_THERM_CTRL_VANA_ON_IN_SLEEP 0x80
+#define PALMAS_OSC_THERM_CTRL_VANA_ON_IN_SLEEP_SHIFT 7
+#define PALMAS_OSC_THERM_CTRL_INT_MASK_IN_SLEEP 0x40
+#define PALMAS_OSC_THERM_CTRL_INT_MASK_IN_SLEEP_SHIFT 6
+#define PALMAS_OSC_THERM_CTRL_RC15MHZ_ON_IN_SLEEP 0x20
+#define PALMAS_OSC_THERM_CTRL_RC15MHZ_ON_IN_SLEEP_SHIFT 5
+#define PALMAS_OSC_THERM_CTRL_THERM_OFF_IN_SLEEP 0x10
+#define PALMAS_OSC_THERM_CTRL_THERM_OFF_IN_SLEEP_SHIFT 4
+#define PALMAS_OSC_THERM_CTRL_THERM_HD_SEL_MASK 0x0c
+#define PALMAS_OSC_THERM_CTRL_THERM_HD_SEL_SHIFT 2
+#define PALMAS_OSC_THERM_CTRL_OSC_BYPASS 0x02
+#define PALMAS_OSC_THERM_CTRL_OSC_BYPASS_SHIFT 1
+#define PALMAS_OSC_THERM_CTRL_OSC_HPMODE 0x01
+#define PALMAS_OSC_THERM_CTRL_OSC_HPMODE_SHIFT 0
+
+/* Bit definitions for BATDEBOUNCING */
+#define PALMAS_BATDEBOUNCING_BAT_DEB_BYPASS 0x80
+#define PALMAS_BATDEBOUNCING_BAT_DEB_BYPASS_SHIFT 7
+#define PALMAS_BATDEBOUNCING_BINS_DEB_MASK 0x78
+#define PALMAS_BATDEBOUNCING_BINS_DEB_SHIFT 3
+#define PALMAS_BATDEBOUNCING_BEXT_DEB_MASK 0x07
+#define PALMAS_BATDEBOUNCING_BEXT_DEB_SHIFT 0
+
+/* Bit definitions for SWOFF_HWRST */
+#define PALMAS_SWOFF_HWRST_PWRON_LPK 0x80
+#define PALMAS_SWOFF_HWRST_PWRON_LPK_SHIFT 7
+#define PALMAS_SWOFF_HWRST_PWRDOWN 0x40
+#define PALMAS_SWOFF_HWRST_PWRDOWN_SHIFT 6
+#define PALMAS_SWOFF_HWRST_WTD 0x20
+#define PALMAS_SWOFF_HWRST_WTD_SHIFT 5
+#define PALMAS_SWOFF_HWRST_TSHUT 0x10
+#define PALMAS_SWOFF_HWRST_TSHUT_SHIFT 4
+#define PALMAS_SWOFF_HWRST_RESET_IN 0x08
+#define PALMAS_SWOFF_HWRST_RESET_IN_SHIFT 3
+#define PALMAS_SWOFF_HWRST_SW_RST 0x04
+#define PALMAS_SWOFF_HWRST_SW_RST_SHIFT 2
+#define PALMAS_SWOFF_HWRST_VSYS_LO 0x02
+#define PALMAS_SWOFF_HWRST_VSYS_LO_SHIFT 1
+#define PALMAS_SWOFF_HWRST_GPADC_SHUTDOWN 0x01
+#define PALMAS_SWOFF_HWRST_GPADC_SHUTDOWN_SHIFT 0
+
+/* Bit definitions for SWOFF_COLDRST */
+#define PALMAS_SWOFF_COLDRST_PWRON_LPK 0x80
+#define PALMAS_SWOFF_COLDRST_PWRON_LPK_SHIFT 7
+#define PALMAS_SWOFF_COLDRST_PWRDOWN 0x40
+#define PALMAS_SWOFF_COLDRST_PWRDOWN_SHIFT 6
+#define PALMAS_SWOFF_COLDRST_WTD 0x20
+#define PALMAS_SWOFF_COLDRST_WTD_SHIFT 5
+#define PALMAS_SWOFF_COLDRST_TSHUT 0x10
+#define PALMAS_SWOFF_COLDRST_TSHUT_SHIFT 4
+#define PALMAS_SWOFF_COLDRST_RESET_IN 0x08
+#define PALMAS_SWOFF_COLDRST_RESET_IN_SHIFT 3
+#define PALMAS_SWOFF_COLDRST_SW_RST 0x04
+#define PALMAS_SWOFF_COLDRST_SW_RST_SHIFT 2
+#define PALMAS_SWOFF_COLDRST_VSYS_LO 0x02
+#define PALMAS_SWOFF_COLDRST_VSYS_LO_SHIFT 1
+#define PALMAS_SWOFF_COLDRST_GPADC_SHUTDOWN 0x01
+#define PALMAS_SWOFF_COLDRST_GPADC_SHUTDOWN_SHIFT 0
+
+/* Bit definitions for SWOFF_STATUS */
+#define PALMAS_SWOFF_STATUS_PWRON_LPK 0x80
+#define PALMAS_SWOFF_STATUS_PWRON_LPK_SHIFT 7
+#define PALMAS_SWOFF_STATUS_PWRDOWN 0x40
+#define PALMAS_SWOFF_STATUS_PWRDOWN_SHIFT 6
+#define PALMAS_SWOFF_STATUS_WTD 0x20
+#define PALMAS_SWOFF_STATUS_WTD_SHIFT 5
+#define PALMAS_SWOFF_STATUS_TSHUT 0x10
+#define PALMAS_SWOFF_STATUS_TSHUT_SHIFT 4
+#define PALMAS_SWOFF_STATUS_RESET_IN 0x08
+#define PALMAS_SWOFF_STATUS_RESET_IN_SHIFT 3
+#define PALMAS_SWOFF_STATUS_SW_RST 0x04
+#define PALMAS_SWOFF_STATUS_SW_RST_SHIFT 2
+#define PALMAS_SWOFF_STATUS_VSYS_LO 0x02
+#define PALMAS_SWOFF_STATUS_VSYS_LO_SHIFT 1
+#define PALMAS_SWOFF_STATUS_GPADC_SHUTDOWN 0x01
+#define PALMAS_SWOFF_STATUS_GPADC_SHUTDOWN_SHIFT 0
+
+/* Bit definitions for PMU_CONFIG */
+#define PALMAS_PMU_CONFIG_MULTI_CELL_EN 0x40
+#define PALMAS_PMU_CONFIG_MULTI_CELL_EN_SHIFT 6
+#define PALMAS_PMU_CONFIG_SPARE_MASK 0x30
+#define PALMAS_PMU_CONFIG_SPARE_SHIFT 4
+#define PALMAS_PMU_CONFIG_SWOFF_DLY_MASK 0x0c
+#define PALMAS_PMU_CONFIG_SWOFF_DLY_SHIFT 2
+#define PALMAS_PMU_CONFIG_GATE_RESET_OUT 0x02
+#define PALMAS_PMU_CONFIG_GATE_RESET_OUT_SHIFT 1
+#define PALMAS_PMU_CONFIG_AUTODEVON 0x01
+#define PALMAS_PMU_CONFIG_AUTODEVON_SHIFT 0
+
+/* Bit definitions for SPARE */
+#define PALMAS_SPARE_SPARE_MASK 0xf8
+#define PALMAS_SPARE_SPARE_SHIFT 3
+#define PALMAS_SPARE_REGEN3_OD 0x04
+#define PALMAS_SPARE_REGEN3_OD_SHIFT 2
+#define PALMAS_SPARE_REGEN2_OD 0x02
+#define PALMAS_SPARE_REGEN2_OD_SHIFT 1
+#define PALMAS_SPARE_REGEN1_OD 0x01
+#define PALMAS_SPARE_REGEN1_OD_SHIFT 0
+
+/* Bit definitions for PMU_SECONDARY_INT */
+#define PALMAS_PMU_SECONDARY_INT_VBUS_OVV_INT_SRC 0x80
+#define PALMAS_PMU_SECONDARY_INT_VBUS_OVV_INT_SRC_SHIFT 7
+#define PALMAS_PMU_SECONDARY_INT_CHARG_DET_N_INT_SRC 0x40
+#define PALMAS_PMU_SECONDARY_INT_CHARG_DET_N_INT_SRC_SHIFT 6
+#define PALMAS_PMU_SECONDARY_INT_BB_INT_SRC 0x20
+#define PALMAS_PMU_SECONDARY_INT_BB_INT_SRC_SHIFT 5
+#define PALMAS_PMU_SECONDARY_INT_FBI_INT_SRC 0x10
+#define PALMAS_PMU_SECONDARY_INT_FBI_INT_SRC_SHIFT 4
+#define PALMAS_PMU_SECONDARY_INT_VBUS_OVV_MASK 0x08
+#define PALMAS_PMU_SECONDARY_INT_VBUS_OVV_MASK_SHIFT 3
+#define PALMAS_PMU_SECONDARY_INT_CHARG_DET_N_MASK 0x04
+#define PALMAS_PMU_SECONDARY_INT_CHARG_DET_N_MASK_SHIFT 2
+#define PALMAS_PMU_SECONDARY_INT_BB_MASK 0x02
+#define PALMAS_PMU_SECONDARY_INT_BB_MASK_SHIFT 1
+#define PALMAS_PMU_SECONDARY_INT_FBI_MASK 0x01
+#define PALMAS_PMU_SECONDARY_INT_FBI_MASK_SHIFT 0
+
+/* Bit definitions for SW_REVISION */
+#define PALMAS_SW_REVISION_SW_REVISION_MASK 0xff
+#define PALMAS_SW_REVISION_SW_REVISION_SHIFT 0
+
+/* Bit definitions for EXT_CHRG_CTRL */
+#define PALMAS_EXT_CHRG_CTRL_VBUS_OVV_STATUS 0x80
+#define PALMAS_EXT_CHRG_CTRL_VBUS_OVV_STATUS_SHIFT 7
+#define PALMAS_EXT_CHRG_CTRL_CHARG_DET_N_STATUS 0x40
+#define PALMAS_EXT_CHRG_CTRL_CHARG_DET_N_STATUS_SHIFT 6
+#define PALMAS_EXT_CHRG_CTRL_VSYS_DEBOUNCE_DELAY 0x08
+#define PALMAS_EXT_CHRG_CTRL_VSYS_DEBOUNCE_DELAY_SHIFT 3
+#define PALMAS_EXT_CHRG_CTRL_CHRG_DET_N 0x04
+#define PALMAS_EXT_CHRG_CTRL_CHRG_DET_N_SHIFT 2
+#define PALMAS_EXT_CHRG_CTRL_AUTO_ACA_EN 0x02
+#define PALMAS_EXT_CHRG_CTRL_AUTO_ACA_EN_SHIFT 1
+#define PALMAS_EXT_CHRG_CTRL_AUTO_LDOUSB_EN 0x01
+#define PALMAS_EXT_CHRG_CTRL_AUTO_LDOUSB_EN_SHIFT 0
+
+/* Bit definitions for PMU_SECONDARY_INT2 */
+#define PALMAS_PMU_SECONDARY_INT2_DVFS2_INT_SRC 0x20
+#define PALMAS_PMU_SECONDARY_INT2_DVFS2_INT_SRC_SHIFT 5
+#define PALMAS_PMU_SECONDARY_INT2_DVFS1_INT_SRC 0x10
+#define PALMAS_PMU_SECONDARY_INT2_DVFS1_INT_SRC_SHIFT 4
+#define PALMAS_PMU_SECONDARY_INT2_DVFS2_MASK 0x02
+#define PALMAS_PMU_SECONDARY_INT2_DVFS2_MASK_SHIFT 1
+#define PALMAS_PMU_SECONDARY_INT2_DVFS1_MASK 0x01
+#define PALMAS_PMU_SECONDARY_INT2_DVFS1_MASK_SHIFT 0
+
+/* Registers for function RESOURCE */
+#define PALMAS_CLK32KG_CTRL 0x0
+#define PALMAS_CLK32KGAUDIO_CTRL 0x1
+#define PALMAS_REGEN1_CTRL 0x2
+#define PALMAS_REGEN2_CTRL 0x3
+#define PALMAS_SYSEN1_CTRL 0x4
+#define PALMAS_SYSEN2_CTRL 0x5
+#define PALMAS_NSLEEP_RES_ASSIGN 0x6
+#define PALMAS_NSLEEP_SMPS_ASSIGN 0x7
+#define PALMAS_NSLEEP_LDO_ASSIGN1 0x8
+#define PALMAS_NSLEEP_LDO_ASSIGN2 0x9
+#define PALMAS_ENABLE1_RES_ASSIGN 0xA
+#define PALMAS_ENABLE1_SMPS_ASSIGN 0xB
+#define PALMAS_ENABLE1_LDO_ASSIGN1 0xC
+#define PALMAS_ENABLE1_LDO_ASSIGN2 0xD
+#define PALMAS_ENABLE2_RES_ASSIGN 0xE
+#define PALMAS_ENABLE2_SMPS_ASSIGN 0xF
+#define PALMAS_ENABLE2_LDO_ASSIGN1 0x10
+#define PALMAS_ENABLE2_LDO_ASSIGN2 0x11
+#define PALMAS_REGEN3_CTRL 0x12
+
+/* Bit definitions for CLK32KG_CTRL */
+#define PALMAS_CLK32KG_CTRL_STATUS 0x10
+#define PALMAS_CLK32KG_CTRL_STATUS_SHIFT 4
+#define PALMAS_CLK32KG_CTRL_MODE_SLEEP 0x04
+#define PALMAS_CLK32KG_CTRL_MODE_SLEEP_SHIFT 2
+#define PALMAS_CLK32KG_CTRL_MODE_ACTIVE 0x01
+#define PALMAS_CLK32KG_CTRL_MODE_ACTIVE_SHIFT 0
+
+/* Bit definitions for CLK32KGAUDIO_CTRL */
+#define PALMAS_CLK32KGAUDIO_CTRL_STATUS 0x10
+#define PALMAS_CLK32KGAUDIO_CTRL_STATUS_SHIFT 4
+#define PALMAS_CLK32KGAUDIO_CTRL_RESERVED3 0x08
+#define PALMAS_CLK32KGAUDIO_CTRL_RESERVED3_SHIFT 3
+#define PALMAS_CLK32KGAUDIO_CTRL_MODE_SLEEP 0x04
+#define PALMAS_CLK32KGAUDIO_CTRL_MODE_SLEEP_SHIFT 2
+#define PALMAS_CLK32KGAUDIO_CTRL_MODE_ACTIVE 0x01
+#define PALMAS_CLK32KGAUDIO_CTRL_MODE_ACTIVE_SHIFT 0
+
+/* Bit definitions for REGEN1_CTRL */
+#define PALMAS_REGEN1_CTRL_STATUS 0x10
+#define PALMAS_REGEN1_CTRL_STATUS_SHIFT 4
+#define PALMAS_REGEN1_CTRL_MODE_SLEEP 0x04
+#define PALMAS_REGEN1_CTRL_MODE_SLEEP_SHIFT 2
+#define PALMAS_REGEN1_CTRL_MODE_ACTIVE 0x01
+#define PALMAS_REGEN1_CTRL_MODE_ACTIVE_SHIFT 0
+
+/* Bit definitions for REGEN2_CTRL */
+#define PALMAS_REGEN2_CTRL_STATUS 0x10
+#define PALMAS_REGEN2_CTRL_STATUS_SHIFT 4
+#define PALMAS_REGEN2_CTRL_MODE_SLEEP 0x04
+#define PALMAS_REGEN2_CTRL_MODE_SLEEP_SHIFT 2
+#define PALMAS_REGEN2_CTRL_MODE_ACTIVE 0x01
+#define PALMAS_REGEN2_CTRL_MODE_ACTIVE_SHIFT 0
+
+/* Bit definitions for SYSEN1_CTRL */
+#define PALMAS_SYSEN1_CTRL_STATUS 0x10
+#define PALMAS_SYSEN1_CTRL_STATUS_SHIFT 4
+#define PALMAS_SYSEN1_CTRL_MODE_SLEEP 0x04
+#define PALMAS_SYSEN1_CTRL_MODE_SLEEP_SHIFT 2
+#define PALMAS_SYSEN1_CTRL_MODE_ACTIVE 0x01
+#define PALMAS_SYSEN1_CTRL_MODE_ACTIVE_SHIFT 0
+
+/* Bit definitions for SYSEN2_CTRL */
+#define PALMAS_SYSEN2_CTRL_STATUS 0x10
+#define PALMAS_SYSEN2_CTRL_STATUS_SHIFT 4
+#define PALMAS_SYSEN2_CTRL_MODE_SLEEP 0x04
+#define PALMAS_SYSEN2_CTRL_MODE_SLEEP_SHIFT 2
+#define PALMAS_SYSEN2_CTRL_MODE_ACTIVE 0x01
+#define PALMAS_SYSEN2_CTRL_MODE_ACTIVE_SHIFT 0
+
+/* Bit definitions for NSLEEP_RES_ASSIGN */
+#define PALMAS_NSLEEP_RES_ASSIGN_REGEN3 0x40
+#define PALMAS_NSLEEP_RES_ASSIGN_REGEN3_SHIFT 6
+#define PALMAS_NSLEEP_RES_ASSIGN_CLK32KGAUDIO 0x20
+#define PALMAS_NSLEEP_RES_ASSIGN_CLK32KGAUDIO_SHIFT 5
+#define PALMAS_NSLEEP_RES_ASSIGN_CLK32KG 0x10
+#define PALMAS_NSLEEP_RES_ASSIGN_CLK32KG_SHIFT 4
+#define PALMAS_NSLEEP_RES_ASSIGN_SYSEN2 0x08
+#define PALMAS_NSLEEP_RES_ASSIGN_SYSEN2_SHIFT 3
+#define PALMAS_NSLEEP_RES_ASSIGN_SYSEN1 0x04
+#define PALMAS_NSLEEP_RES_ASSIGN_SYSEN1_SHIFT 2
+#define PALMAS_NSLEEP_RES_ASSIGN_REGEN2 0x02
+#define PALMAS_NSLEEP_RES_ASSIGN_REGEN2_SHIFT 1
+#define PALMAS_NSLEEP_RES_ASSIGN_REGEN1 0x01
+#define PALMAS_NSLEEP_RES_ASSIGN_REGEN1_SHIFT 0
+
+/* Bit definitions for NSLEEP_SMPS_ASSIGN */
+#define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS10 0x80
+#define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS10_SHIFT 7
+#define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS9 0x40
+#define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS9_SHIFT 6
+#define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS8 0x20
+#define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS8_SHIFT 5
+#define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS7 0x10
+#define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS7_SHIFT 4
+#define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS6 0x08
+#define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS6_SHIFT 3
+#define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS45 0x04
+#define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS45_SHIFT 2
+#define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS3 0x02
+#define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS3_SHIFT 1
+#define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS12 0x01
+#define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS12_SHIFT 0
+
+/* Bit definitions for NSLEEP_LDO_ASSIGN1 */
+#define PALMAS_NSLEEP_LDO_ASSIGN1_LDO8 0x80
+#define PALMAS_NSLEEP_LDO_ASSIGN1_LDO8_SHIFT 7
+#define PALMAS_NSLEEP_LDO_ASSIGN1_LDO7 0x40
+#define PALMAS_NSLEEP_LDO_ASSIGN1_LDO7_SHIFT 6
+#define PALMAS_NSLEEP_LDO_ASSIGN1_LDO6 0x20
+#define PALMAS_NSLEEP_LDO_ASSIGN1_LDO6_SHIFT 5
+#define PALMAS_NSLEEP_LDO_ASSIGN1_LDO5 0x10
+#define PALMAS_NSLEEP_LDO_ASSIGN1_LDO5_SHIFT 4
+#define PALMAS_NSLEEP_LDO_ASSIGN1_LDO4 0x08
+#define PALMAS_NSLEEP_LDO_ASSIGN1_LDO4_SHIFT 3
+#define PALMAS_NSLEEP_LDO_ASSIGN1_LDO3 0x04
+#define PALMAS_NSLEEP_LDO_ASSIGN1_LDO3_SHIFT 2
+#define PALMAS_NSLEEP_LDO_ASSIGN1_LDO2 0x02
+#define PALMAS_NSLEEP_LDO_ASSIGN1_LDO2_SHIFT 1
+#define PALMAS_NSLEEP_LDO_ASSIGN1_LDO1 0x01
+#define PALMAS_NSLEEP_LDO_ASSIGN1_LDO1_SHIFT 0
+
+/* Bit definitions for NSLEEP_LDO_ASSIGN2 */
+#define PALMAS_NSLEEP_LDO_ASSIGN2_LDOUSB 0x04
+#define PALMAS_NSLEEP_LDO_ASSIGN2_LDOUSB_SHIFT 2
+#define PALMAS_NSLEEP_LDO_ASSIGN2_LDOLN 0x02
+#define PALMAS_NSLEEP_LDO_ASSIGN2_LDOLN_SHIFT 1
+#define PALMAS_NSLEEP_LDO_ASSIGN2_LDO9 0x01
+#define PALMAS_NSLEEP_LDO_ASSIGN2_LDO9_SHIFT 0
+
+/* Bit definitions for ENABLE1_RES_ASSIGN */
+#define PALMAS_ENABLE1_RES_ASSIGN_REGEN3 0x40
+#define PALMAS_ENABLE1_RES_ASSIGN_REGEN3_SHIFT 6
+#define PALMAS_ENABLE1_RES_ASSIGN_CLK32KGAUDIO 0x20
+#define PALMAS_ENABLE1_RES_ASSIGN_CLK32KGAUDIO_SHIFT 5
+#define PALMAS_ENABLE1_RES_ASSIGN_CLK32KG 0x10
+#define PALMAS_ENABLE1_RES_ASSIGN_CLK32KG_SHIFT 4
+#define PALMAS_ENABLE1_RES_ASSIGN_SYSEN2 0x08
+#define PALMAS_ENABLE1_RES_ASSIGN_SYSEN2_SHIFT 3
+#define PALMAS_ENABLE1_RES_ASSIGN_SYSEN1 0x04
+#define PALMAS_ENABLE1_RES_ASSIGN_SYSEN1_SHIFT 2
+#define PALMAS_ENABLE1_RES_ASSIGN_REGEN2 0x02
+#define PALMAS_ENABLE1_RES_ASSIGN_REGEN2_SHIFT 1
+#define PALMAS_ENABLE1_RES_ASSIGN_REGEN1 0x01
+#define PALMAS_ENABLE1_RES_ASSIGN_REGEN1_SHIFT 0
+
+/* Bit definitions for ENABLE1_SMPS_ASSIGN */
+#define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS10 0x80
+#define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS10_SHIFT 7
+#define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS9 0x40
+#define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS9_SHIFT 6
+#define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS8 0x20
+#define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS8_SHIFT 5
+#define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS7 0x10
+#define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS7_SHIFT 4
+#define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS6 0x08
+#define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS6_SHIFT 3
+#define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS45 0x04
+#define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS45_SHIFT 2
+#define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS3 0x02
+#define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS3_SHIFT 1
+#define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS12 0x01
+#define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS12_SHIFT 0
+
+/* Bit definitions for ENABLE1_LDO_ASSIGN1 */
+#define PALMAS_ENABLE1_LDO_ASSIGN1_LDO8 0x80
+#define PALMAS_ENABLE1_LDO_ASSIGN1_LDO8_SHIFT 7
+#define PALMAS_ENABLE1_LDO_ASSIGN1_LDO7 0x40
+#define PALMAS_ENABLE1_LDO_ASSIGN1_LDO7_SHIFT 6
+#define PALMAS_ENABLE1_LDO_ASSIGN1_LDO6 0x20
+#define PALMAS_ENABLE1_LDO_ASSIGN1_LDO6_SHIFT 5
+#define PALMAS_ENABLE1_LDO_ASSIGN1_LDO5 0x10
+#define PALMAS_ENABLE1_LDO_ASSIGN1_LDO5_SHIFT 4
+#define PALMAS_ENABLE1_LDO_ASSIGN1_LDO4 0x08
+#define PALMAS_ENABLE1_LDO_ASSIGN1_LDO4_SHIFT 3
+#define PALMAS_ENABLE1_LDO_ASSIGN1_LDO3 0x04
+#define PALMAS_ENABLE1_LDO_ASSIGN1_LDO3_SHIFT 2
+#define PALMAS_ENABLE1_LDO_ASSIGN1_LDO2 0x02
+#define PALMAS_ENABLE1_LDO_ASSIGN1_LDO2_SHIFT 1
+#define PALMAS_ENABLE1_LDO_ASSIGN1_LDO1 0x01
+#define PALMAS_ENABLE1_LDO_ASSIGN1_LDO1_SHIFT 0
+
+/* Bit definitions for ENABLE1_LDO_ASSIGN2 */
+#define PALMAS_ENABLE1_LDO_ASSIGN2_LDOUSB 0x04
+#define PALMAS_ENABLE1_LDO_ASSIGN2_LDOUSB_SHIFT 2
+#define PALMAS_ENABLE1_LDO_ASSIGN2_LDOLN 0x02
+#define PALMAS_ENABLE1_LDO_ASSIGN2_LDOLN_SHIFT 1
+#define PALMAS_ENABLE1_LDO_ASSIGN2_LDO9 0x01
+#define PALMAS_ENABLE1_LDO_ASSIGN2_LDO9_SHIFT 0
+
+/* Bit definitions for ENABLE2_RES_ASSIGN */
+#define PALMAS_ENABLE2_RES_ASSIGN_REGEN3 0x40
+#define PALMAS_ENABLE2_RES_ASSIGN_REGEN3_SHIFT 6
+#define PALMAS_ENABLE2_RES_ASSIGN_CLK32KGAUDIO 0x20
+#define PALMAS_ENABLE2_RES_ASSIGN_CLK32KGAUDIO_SHIFT 5
+#define PALMAS_ENABLE2_RES_ASSIGN_CLK32KG 0x10
+#define PALMAS_ENABLE2_RES_ASSIGN_CLK32KG_SHIFT 4
+#define PALMAS_ENABLE2_RES_ASSIGN_SYSEN2 0x08
+#define PALMAS_ENABLE2_RES_ASSIGN_SYSEN2_SHIFT 3
+#define PALMAS_ENABLE2_RES_ASSIGN_SYSEN1 0x04
+#define PALMAS_ENABLE2_RES_ASSIGN_SYSEN1_SHIFT 2
+#define PALMAS_ENABLE2_RES_ASSIGN_REGEN2 0x02
+#define PALMAS_ENABLE2_RES_ASSIGN_REGEN2_SHIFT 1
+#define PALMAS_ENABLE2_RES_ASSIGN_REGEN1 0x01
+#define PALMAS_ENABLE2_RES_ASSIGN_REGEN1_SHIFT 0
+
+/* Bit definitions for ENABLE2_SMPS_ASSIGN */
+#define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS10 0x80
+#define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS10_SHIFT 7
+#define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS9 0x40
+#define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS9_SHIFT 6
+#define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS8 0x20
+#define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS8_SHIFT 5
+#define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS7 0x10
+#define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS7_SHIFT 4
+#define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS6 0x08
+#define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS6_SHIFT 3
+#define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS45 0x04
+#define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS45_SHIFT 2
+#define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS3 0x02
+#define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS3_SHIFT 1
+#define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS12 0x01
+#define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS12_SHIFT 0
+
+/* Bit definitions for ENABLE2_LDO_ASSIGN1 */
+#define PALMAS_ENABLE2_LDO_ASSIGN1_LDO8 0x80
+#define PALMAS_ENABLE2_LDO_ASSIGN1_LDO8_SHIFT 7
+#define PALMAS_ENABLE2_LDO_ASSIGN1_LDO7 0x40
+#define PALMAS_ENABLE2_LDO_ASSIGN1_LDO7_SHIFT 6
+#define PALMAS_ENABLE2_LDO_ASSIGN1_LDO6 0x20
+#define PALMAS_ENABLE2_LDO_ASSIGN1_LDO6_SHIFT 5
+#define PALMAS_ENABLE2_LDO_ASSIGN1_LDO5 0x10
+#define PALMAS_ENABLE2_LDO_ASSIGN1_LDO5_SHIFT 4
+#define PALMAS_ENABLE2_LDO_ASSIGN1_LDO4 0x08
+#define PALMAS_ENABLE2_LDO_ASSIGN1_LDO4_SHIFT 3
+#define PALMAS_ENABLE2_LDO_ASSIGN1_LDO3 0x04
+#define PALMAS_ENABLE2_LDO_ASSIGN1_LDO3_SHIFT 2
+#define PALMAS_ENABLE2_LDO_ASSIGN1_LDO2 0x02
+#define PALMAS_ENABLE2_LDO_ASSIGN1_LDO2_SHIFT 1
+#define PALMAS_ENABLE2_LDO_ASSIGN1_LDO1 0x01
+#define PALMAS_ENABLE2_LDO_ASSIGN1_LDO1_SHIFT 0
+
+/* Bit definitions for ENABLE2_LDO_ASSIGN2 */
+#define PALMAS_ENABLE2_LDO_ASSIGN2_LDOUSB 0x04
+#define PALMAS_ENABLE2_LDO_ASSIGN2_LDOUSB_SHIFT 2
+#define PALMAS_ENABLE2_LDO_ASSIGN2_LDOLN 0x02
+#define PALMAS_ENABLE2_LDO_ASSIGN2_LDOLN_SHIFT 1
+#define PALMAS_ENABLE2_LDO_ASSIGN2_LDO9 0x01
+#define PALMAS_ENABLE2_LDO_ASSIGN2_LDO9_SHIFT 0
+
+/* Bit definitions for REGEN3_CTRL */
+#define PALMAS_REGEN3_CTRL_STATUS 0x10
+#define PALMAS_REGEN3_CTRL_STATUS_SHIFT 4
+#define PALMAS_REGEN3_CTRL_MODE_SLEEP 0x04
+#define PALMAS_REGEN3_CTRL_MODE_SLEEP_SHIFT 2
+#define PALMAS_REGEN3_CTRL_MODE_ACTIVE 0x01
+#define PALMAS_REGEN3_CTRL_MODE_ACTIVE_SHIFT 0
+
+/* Registers for function PAD_CONTROL */
+#define PALMAS_PU_PD_INPUT_CTRL1 0x0
+#define PALMAS_PU_PD_INPUT_CTRL2 0x1
+#define PALMAS_PU_PD_INPUT_CTRL3 0x2
+#define PALMAS_OD_OUTPUT_CTRL 0x4
+#define PALMAS_POLARITY_CTRL 0x5
+#define PALMAS_PRIMARY_SECONDARY_PAD1 0x6
+#define PALMAS_PRIMARY_SECONDARY_PAD2 0x7
+#define PALMAS_I2C_SPI 0x8
+#define PALMAS_PU_PD_INPUT_CTRL4 0x9
+#define PALMAS_PRIMARY_SECONDARY_PAD3 0xA
+
+/* Bit definitions for PU_PD_INPUT_CTRL1 */
+#define PALMAS_PU_PD_INPUT_CTRL1_RESET_IN_PD 0x40
+#define PALMAS_PU_PD_INPUT_CTRL1_RESET_IN_PD_SHIFT 6
+#define PALMAS_PU_PD_INPUT_CTRL1_GPADC_START_PU 0x20
+#define PALMAS_PU_PD_INPUT_CTRL1_GPADC_START_PU_SHIFT 5
+#define PALMAS_PU_PD_INPUT_CTRL1_GPADC_START_PD 0x10
+#define PALMAS_PU_PD_INPUT_CTRL1_GPADC_START_PD_SHIFT 4
+#define PALMAS_PU_PD_INPUT_CTRL1_PWRDOWN_PD 0x04
+#define PALMAS_PU_PD_INPUT_CTRL1_PWRDOWN_PD_SHIFT 2
+#define PALMAS_PU_PD_INPUT_CTRL1_NRESWARM_PU 0x02
+#define PALMAS_PU_PD_INPUT_CTRL1_NRESWARM_PU_SHIFT 1
+
+/* Bit definitions for PU_PD_INPUT_CTRL2 */
+#define PALMAS_PU_PD_INPUT_CTRL2_ENABLE2_PU 0x20
+#define PALMAS_PU_PD_INPUT_CTRL2_ENABLE2_PU_SHIFT 5
+#define PALMAS_PU_PD_INPUT_CTRL2_ENABLE2_PD 0x10
+#define PALMAS_PU_PD_INPUT_CTRL2_ENABLE2_PD_SHIFT 4
+#define PALMAS_PU_PD_INPUT_CTRL2_ENABLE1_PU 0x08
+#define PALMAS_PU_PD_INPUT_CTRL2_ENABLE1_PU_SHIFT 3
+#define PALMAS_PU_PD_INPUT_CTRL2_ENABLE1_PD 0x04
+#define PALMAS_PU_PD_INPUT_CTRL2_ENABLE1_PD_SHIFT 2
+#define PALMAS_PU_PD_INPUT_CTRL2_NSLEEP_PU 0x02
+#define PALMAS_PU_PD_INPUT_CTRL2_NSLEEP_PU_SHIFT 1
+#define PALMAS_PU_PD_INPUT_CTRL2_NSLEEP_PD 0x01
+#define PALMAS_PU_PD_INPUT_CTRL2_NSLEEP_PD_SHIFT 0
+
+/* Bit definitions for PU_PD_INPUT_CTRL3 */
+#define PALMAS_PU_PD_INPUT_CTRL3_ACOK_PD 0x40
+#define PALMAS_PU_PD_INPUT_CTRL3_ACOK_PD_SHIFT 6
+#define PALMAS_PU_PD_INPUT_CTRL3_CHRG_DET_N_PD 0x10
+#define PALMAS_PU_PD_INPUT_CTRL3_CHRG_DET_N_PD_SHIFT 4
+#define PALMAS_PU_PD_INPUT_CTRL3_POWERHOLD_PD 0x04
+#define PALMAS_PU_PD_INPUT_CTRL3_POWERHOLD_PD_SHIFT 2
+#define PALMAS_PU_PD_INPUT_CTRL3_MSECURE_PD 0x01
+#define PALMAS_PU_PD_INPUT_CTRL3_MSECURE_PD_SHIFT 0
+
+/* Bit definitions for OD_OUTPUT_CTRL */
+#define PALMAS_OD_OUTPUT_CTRL_PWM_2_OD 0x80
+#define PALMAS_OD_OUTPUT_CTRL_PWM_2_OD_SHIFT 7
+#define PALMAS_OD_OUTPUT_CTRL_VBUSDET_OD 0x40
+#define PALMAS_OD_OUTPUT_CTRL_VBUSDET_OD_SHIFT 6
+#define PALMAS_OD_OUTPUT_CTRL_PWM_1_OD 0x20
+#define PALMAS_OD_OUTPUT_CTRL_PWM_1_OD_SHIFT 5
+#define PALMAS_OD_OUTPUT_CTRL_INT_OD 0x08
+#define PALMAS_OD_OUTPUT_CTRL_INT_OD_SHIFT 3
+
+/* Bit definitions for POLARITY_CTRL */
+#define PALMAS_POLARITY_CTRL_INT_POLARITY 0x80
+#define PALMAS_POLARITY_CTRL_INT_POLARITY_SHIFT 7
+#define PALMAS_POLARITY_CTRL_ENABLE2_POLARITY 0x40
+#define PALMAS_POLARITY_CTRL_ENABLE2_POLARITY_SHIFT 6
+#define PALMAS_POLARITY_CTRL_ENABLE1_POLARITY 0x20
+#define PALMAS_POLARITY_CTRL_ENABLE1_POLARITY_SHIFT 5
+#define PALMAS_POLARITY_CTRL_NSLEEP_POLARITY 0x10
+#define PALMAS_POLARITY_CTRL_NSLEEP_POLARITY_SHIFT 4
+#define PALMAS_POLARITY_CTRL_RESET_IN_POLARITY 0x08
+#define PALMAS_POLARITY_CTRL_RESET_IN_POLARITY_SHIFT 3
+#define PALMAS_POLARITY_CTRL_GPIO_3_CHRG_DET_N_POLARITY 0x04
+#define PALMAS_POLARITY_CTRL_GPIO_3_CHRG_DET_N_POLARITY_SHIFT 2
+#define PALMAS_POLARITY_CTRL_POWERGOOD_USB_PSEL_POLARITY 0x02
+#define PALMAS_POLARITY_CTRL_POWERGOOD_USB_PSEL_POLARITY_SHIFT 1
+#define PALMAS_POLARITY_CTRL_PWRDOWN_POLARITY 0x01
+#define PALMAS_POLARITY_CTRL_PWRDOWN_POLARITY_SHIFT 0
+
+/* Bit definitions for PRIMARY_SECONDARY_PAD1 */
+#define PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_3 0x80
+#define PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_3_SHIFT 7
+#define PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_MASK 0x60
+#define PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_SHIFT 5
+#define PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_MASK 0x18
+#define PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_SHIFT 3
+#define PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_0 0x04
+#define PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_0_SHIFT 2
+#define PALMAS_PRIMARY_SECONDARY_PAD1_VAC 0x02
+#define PALMAS_PRIMARY_SECONDARY_PAD1_VAC_SHIFT 1
+#define PALMAS_PRIMARY_SECONDARY_PAD1_POWERGOOD 0x01
+#define PALMAS_PRIMARY_SECONDARY_PAD1_POWERGOOD_SHIFT 0
+
+/* Bit definitions for PRIMARY_SECONDARY_PAD2 */
+#define PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_7_MASK 0x30
+#define PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_7_SHIFT 4
+#define PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_6 0x08
+#define PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_6_SHIFT 3
+#define PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_5_MASK 0x06
+#define PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_5_SHIFT 1
+#define PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_4 0x01
+#define PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_4_SHIFT 0
+
+/* Bit definitions for I2C_SPI */
+#define PALMAS_I2C_SPI_I2C2OTP_EN 0x80
+#define PALMAS_I2C_SPI_I2C2OTP_EN_SHIFT 7
+#define PALMAS_I2C_SPI_I2C2OTP_PAGESEL 0x40
+#define PALMAS_I2C_SPI_I2C2OTP_PAGESEL_SHIFT 6
+#define PALMAS_I2C_SPI_ID_I2C2 0x20
+#define PALMAS_I2C_SPI_ID_I2C2_SHIFT 5
+#define PALMAS_I2C_SPI_I2C_SPI 0x10
+#define PALMAS_I2C_SPI_I2C_SPI_SHIFT 4
+#define PALMAS_I2C_SPI_ID_I2C1_MASK 0x0f
+#define PALMAS_I2C_SPI_ID_I2C1_SHIFT 0
+
+/* Bit definitions for PU_PD_INPUT_CTRL4 */
+#define PALMAS_PU_PD_INPUT_CTRL4_DVFS2_DAT_PD 0x40
+#define PALMAS_PU_PD_INPUT_CTRL4_DVFS2_DAT_PD_SHIFT 6
+#define PALMAS_PU_PD_INPUT_CTRL4_DVFS2_CLK_PD 0x10
+#define PALMAS_PU_PD_INPUT_CTRL4_DVFS2_CLK_PD_SHIFT 4
+#define PALMAS_PU_PD_INPUT_CTRL4_DVFS1_DAT_PD 0x04
+#define PALMAS_PU_PD_INPUT_CTRL4_DVFS1_DAT_PD_SHIFT 2
+#define PALMAS_PU_PD_INPUT_CTRL4_DVFS1_CLK_PD 0x01
+#define PALMAS_PU_PD_INPUT_CTRL4_DVFS1_CLK_PD_SHIFT 0
+
+/* Bit definitions for PRIMARY_SECONDARY_PAD3 */
+#define PALMAS_PRIMARY_SECONDARY_PAD3_DVFS2 0x02
+#define PALMAS_PRIMARY_SECONDARY_PAD3_DVFS2_SHIFT 1
+#define PALMAS_PRIMARY_SECONDARY_PAD3_DVFS1 0x01
+#define PALMAS_PRIMARY_SECONDARY_PAD3_DVFS1_SHIFT 0
+
+/* Registers for function LED_PWM */
+#define PALMAS_LED_PERIOD_CTRL 0x0
+#define PALMAS_LED_CTRL 0x1
+#define PALMAS_PWM_CTRL1 0x2
+#define PALMAS_PWM_CTRL2 0x3
+
+/* Bit definitions for LED_PERIOD_CTRL */
+#define PALMAS_LED_PERIOD_CTRL_LED_2_PERIOD_MASK 0x38
+#define PALMAS_LED_PERIOD_CTRL_LED_2_PERIOD_SHIFT 3
+#define PALMAS_LED_PERIOD_CTRL_LED_1_PERIOD_MASK 0x07
+#define PALMAS_LED_PERIOD_CTRL_LED_1_PERIOD_SHIFT 0
+
+/* Bit definitions for LED_CTRL */
+#define PALMAS_LED_CTRL_LED_2_SEQ 0x20
+#define PALMAS_LED_CTRL_LED_2_SEQ_SHIFT 5
+#define PALMAS_LED_CTRL_LED_1_SEQ 0x10
+#define PALMAS_LED_CTRL_LED_1_SEQ_SHIFT 4
+#define PALMAS_LED_CTRL_LED_2_ON_TIME_MASK 0x0c
+#define PALMAS_LED_CTRL_LED_2_ON_TIME_SHIFT 2
+#define PALMAS_LED_CTRL_LED_1_ON_TIME_MASK 0x03
+#define PALMAS_LED_CTRL_LED_1_ON_TIME_SHIFT 0
+
+/* Bit definitions for PWM_CTRL1 */
+#define PALMAS_PWM_CTRL1_PWM_FREQ_EN 0x02
+#define PALMAS_PWM_CTRL1_PWM_FREQ_EN_SHIFT 1
+#define PALMAS_PWM_CTRL1_PWM_FREQ_SEL 0x01
+#define PALMAS_PWM_CTRL1_PWM_FREQ_SEL_SHIFT 0
+
+/* Bit definitions for PWM_CTRL2 */
+#define PALMAS_PWM_CTRL2_PWM_DUTY_SEL_MASK 0xff
+#define PALMAS_PWM_CTRL2_PWM_DUTY_SEL_SHIFT 0
+
+/* Registers for function INTERRUPT */
+#define PALMAS_INT1_STATUS 0x0
+#define PALMAS_INT1_MASK 0x1
+#define PALMAS_INT1_LINE_STATE 0x2
+#define PALMAS_INT1_EDGE_DETECT1_RESERVED 0x3
+#define PALMAS_INT1_EDGE_DETECT2_RESERVED 0x4
+#define PALMAS_INT2_STATUS 0x5
+#define PALMAS_INT2_MASK 0x6
+#define PALMAS_INT2_LINE_STATE 0x7
+#define PALMAS_INT2_EDGE_DETECT1_RESERVED 0x8
+#define PALMAS_INT2_EDGE_DETECT2_RESERVED 0x9
+#define PALMAS_INT3_STATUS 0xA
+#define PALMAS_INT3_MASK 0xB
+#define PALMAS_INT3_LINE_STATE 0xC
+#define PALMAS_INT3_EDGE_DETECT1_RESERVED 0xD
+#define PALMAS_INT3_EDGE_DETECT2_RESERVED 0xE
+#define PALMAS_INT4_STATUS 0xF
+#define PALMAS_INT4_MASK 0x10
+#define PALMAS_INT4_LINE_STATE 0x11
+#define PALMAS_INT4_EDGE_DETECT1 0x12
+#define PALMAS_INT4_EDGE_DETECT2 0x13
+#define PALMAS_INT_CTRL 0x14
+
+/* Bit definitions for INT1_STATUS */
+#define PALMAS_INT1_STATUS_VBAT_MON 0x80
+#define PALMAS_INT1_STATUS_VBAT_MON_SHIFT 7
+#define PALMAS_INT1_STATUS_VSYS_MON 0x40
+#define PALMAS_INT1_STATUS_VSYS_MON_SHIFT 6
+#define PALMAS_INT1_STATUS_HOTDIE 0x20
+#define PALMAS_INT1_STATUS_HOTDIE_SHIFT 5
+#define PALMAS_INT1_STATUS_PWRDOWN 0x10
+#define PALMAS_INT1_STATUS_PWRDOWN_SHIFT 4
+#define PALMAS_INT1_STATUS_RPWRON 0x08
+#define PALMAS_INT1_STATUS_RPWRON_SHIFT 3
+#define PALMAS_INT1_STATUS_LONG_PRESS_KEY 0x04
+#define PALMAS_INT1_STATUS_LONG_PRESS_KEY_SHIFT 2
+#define PALMAS_INT1_STATUS_PWRON 0x02
+#define PALMAS_INT1_STATUS_PWRON_SHIFT 1
+#define PALMAS_INT1_STATUS_CHARG_DET_N_VBUS_OVV 0x01
+#define PALMAS_INT1_STATUS_CHARG_DET_N_VBUS_OVV_SHIFT 0
+
+/* Bit definitions for INT1_MASK */
+#define PALMAS_INT1_MASK_VBAT_MON 0x80
+#define PALMAS_INT1_MASK_VBAT_MON_SHIFT 7
+#define PALMAS_INT1_MASK_VSYS_MON 0x40
+#define PALMAS_INT1_MASK_VSYS_MON_SHIFT 6
+#define PALMAS_INT1_MASK_HOTDIE 0x20
+#define PALMAS_INT1_MASK_HOTDIE_SHIFT 5
+#define PALMAS_INT1_MASK_PWRDOWN 0x10
+#define PALMAS_INT1_MASK_PWRDOWN_SHIFT 4
+#define PALMAS_INT1_MASK_RPWRON 0x08
+#define PALMAS_INT1_MASK_RPWRON_SHIFT 3
+#define PALMAS_INT1_MASK_LONG_PRESS_KEY 0x04
+#define PALMAS_INT1_MASK_LONG_PRESS_KEY_SHIFT 2
+#define PALMAS_INT1_MASK_PWRON 0x02
+#define PALMAS_INT1_MASK_PWRON_SHIFT 1
+#define PALMAS_INT1_MASK_CHARG_DET_N_VBUS_OVV 0x01
+#define PALMAS_INT1_MASK_CHARG_DET_N_VBUS_OVV_SHIFT 0
+
+/* Bit definitions for INT1_LINE_STATE */
+#define PALMAS_INT1_LINE_STATE_VBAT_MON 0x80
+#define PALMAS_INT1_LINE_STATE_VBAT_MON_SHIFT 7
+#define PALMAS_INT1_LINE_STATE_VSYS_MON 0x40
+#define PALMAS_INT1_LINE_STATE_VSYS_MON_SHIFT 6
+#define PALMAS_INT1_LINE_STATE_HOTDIE 0x20
+#define PALMAS_INT1_LINE_STATE_HOTDIE_SHIFT 5
+#define PALMAS_INT1_LINE_STATE_PWRDOWN 0x10
+#define PALMAS_INT1_LINE_STATE_PWRDOWN_SHIFT 4
+#define PALMAS_INT1_LINE_STATE_RPWRON 0x08
+#define PALMAS_INT1_LINE_STATE_RPWRON_SHIFT 3
+#define PALMAS_INT1_LINE_STATE_LONG_PRESS_KEY 0x04
+#define PALMAS_INT1_LINE_STATE_LONG_PRESS_KEY_SHIFT 2
+#define PALMAS_INT1_LINE_STATE_PWRON 0x02
+#define PALMAS_INT1_LINE_STATE_PWRON_SHIFT 1
+#define PALMAS_INT1_LINE_STATE_CHARG_DET_N_VBUS_OVV 0x01
+#define PALMAS_INT1_LINE_STATE_CHARG_DET_N_VBUS_OVV_SHIFT 0
+
+/* Bit definitions for INT2_STATUS */
+#define PALMAS_INT2_STATUS_VAC_ACOK 0x80
+#define PALMAS_INT2_STATUS_VAC_ACOK_SHIFT 7
+#define PALMAS_INT2_STATUS_SHORT 0x40
+#define PALMAS_INT2_STATUS_SHORT_SHIFT 6
+#define PALMAS_INT2_STATUS_FBI_BB 0x20
+#define PALMAS_INT2_STATUS_FBI_BB_SHIFT 5
+#define PALMAS_INT2_STATUS_RESET_IN 0x10
+#define PALMAS_INT2_STATUS_RESET_IN_SHIFT 4
+#define PALMAS_INT2_STATUS_BATREMOVAL 0x08
+#define PALMAS_INT2_STATUS_BATREMOVAL_SHIFT 3
+#define PALMAS_INT2_STATUS_WDT 0x04
+#define PALMAS_INT2_STATUS_WDT_SHIFT 2
+#define PALMAS_INT2_STATUS_RTC_TIMER 0x02
+#define PALMAS_INT2_STATUS_RTC_TIMER_SHIFT 1
+#define PALMAS_INT2_STATUS_RTC_ALARM 0x01
+#define PALMAS_INT2_STATUS_RTC_ALARM_SHIFT 0
+
+/* Bit definitions for INT2_MASK */
+#define PALMAS_INT2_MASK_VAC_ACOK 0x80
+#define PALMAS_INT2_MASK_VAC_ACOK_SHIFT 7
+#define PALMAS_INT2_MASK_SHORT 0x40
+#define PALMAS_INT2_MASK_SHORT_SHIFT 6
+#define PALMAS_INT2_MASK_FBI_BB 0x20
+#define PALMAS_INT2_MASK_FBI_BB_SHIFT 5
+#define PALMAS_INT2_MASK_RESET_IN 0x10
+#define PALMAS_INT2_MASK_RESET_IN_SHIFT 4
+#define PALMAS_INT2_MASK_BATREMOVAL 0x08
+#define PALMAS_INT2_MASK_BATREMOVAL_SHIFT 3
+#define PALMAS_INT2_MASK_WDT 0x04
+#define PALMAS_INT2_MASK_WDT_SHIFT 2
+#define PALMAS_INT2_MASK_RTC_TIMER 0x02
+#define PALMAS_INT2_MASK_RTC_TIMER_SHIFT 1
+#define PALMAS_INT2_MASK_RTC_ALARM 0x01
+#define PALMAS_INT2_MASK_RTC_ALARM_SHIFT 0
+
+/* Bit definitions for INT2_LINE_STATE */
+#define PALMAS_INT2_LINE_STATE_VAC_ACOK 0x80
+#define PALMAS_INT2_LINE_STATE_VAC_ACOK_SHIFT 7
+#define PALMAS_INT2_LINE_STATE_SHORT 0x40
+#define PALMAS_INT2_LINE_STATE_SHORT_SHIFT 6
+#define PALMAS_INT2_LINE_STATE_FBI_BB 0x20
+#define PALMAS_INT2_LINE_STATE_FBI_BB_SHIFT 5
+#define PALMAS_INT2_LINE_STATE_RESET_IN 0x10
+#define PALMAS_INT2_LINE_STATE_RESET_IN_SHIFT 4
+#define PALMAS_INT2_LINE_STATE_BATREMOVAL 0x08
+#define PALMAS_INT2_LINE_STATE_BATREMOVAL_SHIFT 3
+#define PALMAS_INT2_LINE_STATE_WDT 0x04
+#define PALMAS_INT2_LINE_STATE_WDT_SHIFT 2
+#define PALMAS_INT2_LINE_STATE_RTC_TIMER 0x02
+#define PALMAS_INT2_LINE_STATE_RTC_TIMER_SHIFT 1
+#define PALMAS_INT2_LINE_STATE_RTC_ALARM 0x01
+#define PALMAS_INT2_LINE_STATE_RTC_ALARM_SHIFT 0
+
+/* Bit definitions for INT3_STATUS */
+#define PALMAS_INT3_STATUS_VBUS 0x80
+#define PALMAS_INT3_STATUS_VBUS_SHIFT 7
+#define PALMAS_INT3_STATUS_VBUS_OTG 0x40
+#define PALMAS_INT3_STATUS_VBUS_OTG_SHIFT 6
+#define PALMAS_INT3_STATUS_ID 0x20
+#define PALMAS_INT3_STATUS_ID_SHIFT 5
+#define PALMAS_INT3_STATUS_ID_OTG 0x10
+#define PALMAS_INT3_STATUS_ID_OTG_SHIFT 4
+#define PALMAS_INT3_STATUS_GPADC_EOC_RT 0x08
+#define PALMAS_INT3_STATUS_GPADC_EOC_RT_SHIFT 3
+#define PALMAS_INT3_STATUS_GPADC_EOC_SW 0x04
+#define PALMAS_INT3_STATUS_GPADC_EOC_SW_SHIFT 2
+#define PALMAS_INT3_STATUS_GPADC_AUTO_1 0x02
+#define PALMAS_INT3_STATUS_GPADC_AUTO_1_SHIFT 1
+#define PALMAS_INT3_STATUS_GPADC_AUTO_0 0x01
+#define PALMAS_INT3_STATUS_GPADC_AUTO_0_SHIFT 0
+
+/* Bit definitions for INT3_MASK */
+#define PALMAS_INT3_MASK_VBUS 0x80
+#define PALMAS_INT3_MASK_VBUS_SHIFT 7
+#define PALMAS_INT3_MASK_VBUS_OTG 0x40
+#define PALMAS_INT3_MASK_VBUS_OTG_SHIFT 6
+#define PALMAS_INT3_MASK_ID 0x20
+#define PALMAS_INT3_MASK_ID_SHIFT 5
+#define PALMAS_INT3_MASK_ID_OTG 0x10
+#define PALMAS_INT3_MASK_ID_OTG_SHIFT 4
+#define PALMAS_INT3_MASK_GPADC_EOC_RT 0x08
+#define PALMAS_INT3_MASK_GPADC_EOC_RT_SHIFT 3
+#define PALMAS_INT3_MASK_GPADC_EOC_SW 0x04
+#define PALMAS_INT3_MASK_GPADC_EOC_SW_SHIFT 2
+#define PALMAS_INT3_MASK_GPADC_AUTO_1 0x02
+#define PALMAS_INT3_MASK_GPADC_AUTO_1_SHIFT 1
+#define PALMAS_INT3_MASK_GPADC_AUTO_0 0x01
+#define PALMAS_INT3_MASK_GPADC_AUTO_0_SHIFT 0
+
+/* Bit definitions for INT3_LINE_STATE */
+#define PALMAS_INT3_LINE_STATE_VBUS 0x80
+#define PALMAS_INT3_LINE_STATE_VBUS_SHIFT 7
+#define PALMAS_INT3_LINE_STATE_VBUS_OTG 0x40
+#define PALMAS_INT3_LINE_STATE_VBUS_OTG_SHIFT 6
+#define PALMAS_INT3_LINE_STATE_ID 0x20
+#define PALMAS_INT3_LINE_STATE_ID_SHIFT 5
+#define PALMAS_INT3_LINE_STATE_ID_OTG 0x10
+#define PALMAS_INT3_LINE_STATE_ID_OTG_SHIFT 4
+#define PALMAS_INT3_LINE_STATE_GPADC_EOC_RT 0x08
+#define PALMAS_INT3_LINE_STATE_GPADC_EOC_RT_SHIFT 3
+#define PALMAS_INT3_LINE_STATE_GPADC_EOC_SW 0x04
+#define PALMAS_INT3_LINE_STATE_GPADC_EOC_SW_SHIFT 2
+#define PALMAS_INT3_LINE_STATE_GPADC_AUTO_1 0x02
+#define PALMAS_INT3_LINE_STATE_GPADC_AUTO_1_SHIFT 1
+#define PALMAS_INT3_LINE_STATE_GPADC_AUTO_0 0x01
+#define PALMAS_INT3_LINE_STATE_GPADC_AUTO_0_SHIFT 0
+
+/* Bit definitions for INT4_STATUS */
+#define PALMAS_INT4_STATUS_GPIO_7 0x80
+#define PALMAS_INT4_STATUS_GPIO_7_SHIFT 7
+#define PALMAS_INT4_STATUS_GPIO_6 0x40
+#define PALMAS_INT4_STATUS_GPIO_6_SHIFT 6
+#define PALMAS_INT4_STATUS_GPIO_5 0x20
+#define PALMAS_INT4_STATUS_GPIO_5_SHIFT 5
+#define PALMAS_INT4_STATUS_GPIO_4 0x10
+#define PALMAS_INT4_STATUS_GPIO_4_SHIFT 4
+#define PALMAS_INT4_STATUS_GPIO_3 0x08
+#define PALMAS_INT4_STATUS_GPIO_3_SHIFT 3
+#define PALMAS_INT4_STATUS_GPIO_2 0x04
+#define PALMAS_INT4_STATUS_GPIO_2_SHIFT 2
+#define PALMAS_INT4_STATUS_GPIO_1 0x02
+#define PALMAS_INT4_STATUS_GPIO_1_SHIFT 1
+#define PALMAS_INT4_STATUS_GPIO_0 0x01
+#define PALMAS_INT4_STATUS_GPIO_0_SHIFT 0
+
+/* Bit definitions for INT4_MASK */
+#define PALMAS_INT4_MASK_GPIO_7 0x80
+#define PALMAS_INT4_MASK_GPIO_7_SHIFT 7
+#define PALMAS_INT4_MASK_GPIO_6 0x40
+#define PALMAS_INT4_MASK_GPIO_6_SHIFT 6
+#define PALMAS_INT4_MASK_GPIO_5 0x20
+#define PALMAS_INT4_MASK_GPIO_5_SHIFT 5
+#define PALMAS_INT4_MASK_GPIO_4 0x10
+#define PALMAS_INT4_MASK_GPIO_4_SHIFT 4
+#define PALMAS_INT4_MASK_GPIO_3 0x08
+#define PALMAS_INT4_MASK_GPIO_3_SHIFT 3
+#define PALMAS_INT4_MASK_GPIO_2 0x04
+#define PALMAS_INT4_MASK_GPIO_2_SHIFT 2
+#define PALMAS_INT4_MASK_GPIO_1 0x02
+#define PALMAS_INT4_MASK_GPIO_1_SHIFT 1
+#define PALMAS_INT4_MASK_GPIO_0 0x01
+#define PALMAS_INT4_MASK_GPIO_0_SHIFT 0
+
+/* Bit definitions for INT4_LINE_STATE */
+#define PALMAS_INT4_LINE_STATE_GPIO_7 0x80
+#define PALMAS_INT4_LINE_STATE_GPIO_7_SHIFT 7
+#define PALMAS_INT4_LINE_STATE_GPIO_6 0x40
+#define PALMAS_INT4_LINE_STATE_GPIO_6_SHIFT 6
+#define PALMAS_INT4_LINE_STATE_GPIO_5 0x20
+#define PALMAS_INT4_LINE_STATE_GPIO_5_SHIFT 5
+#define PALMAS_INT4_LINE_STATE_GPIO_4 0x10
+#define PALMAS_INT4_LINE_STATE_GPIO_4_SHIFT 4
+#define PALMAS_INT4_LINE_STATE_GPIO_3 0x08
+#define PALMAS_INT4_LINE_STATE_GPIO_3_SHIFT 3
+#define PALMAS_INT4_LINE_STATE_GPIO_2 0x04
+#define PALMAS_INT4_LINE_STATE_GPIO_2_SHIFT 2
+#define PALMAS_INT4_LINE_STATE_GPIO_1 0x02
+#define PALMAS_INT4_LINE_STATE_GPIO_1_SHIFT 1
+#define PALMAS_INT4_LINE_STATE_GPIO_0 0x01
+#define PALMAS_INT4_LINE_STATE_GPIO_0_SHIFT 0
+
+/* Bit definitions for INT4_EDGE_DETECT1 */
+#define PALMAS_INT4_EDGE_DETECT1_GPIO_3_RISING 0x80
+#define PALMAS_INT4_EDGE_DETECT1_GPIO_3_RISING_SHIFT 7
+#define PALMAS_INT4_EDGE_DETECT1_GPIO_3_FALLING 0x40
+#define PALMAS_INT4_EDGE_DETECT1_GPIO_3_FALLING_SHIFT 6
+#define PALMAS_INT4_EDGE_DETECT1_GPIO_2_RISING 0x20
+#define PALMAS_INT4_EDGE_DETECT1_GPIO_2_RISING_SHIFT 5
+#define PALMAS_INT4_EDGE_DETECT1_GPIO_2_FALLING 0x10
+#define PALMAS_INT4_EDGE_DETECT1_GPIO_2_FALLING_SHIFT 4
+#define PALMAS_INT4_EDGE_DETECT1_GPIO_1_RISING 0x08
+#define PALMAS_INT4_EDGE_DETECT1_GPIO_1_RISING_SHIFT 3
+#define PALMAS_INT4_EDGE_DETECT1_GPIO_1_FALLING 0x04
+#define PALMAS_INT4_EDGE_DETECT1_GPIO_1_FALLING_SHIFT 2
+#define PALMAS_INT4_EDGE_DETECT1_GPIO_0_RISING 0x02
+#define PALMAS_INT4_EDGE_DETECT1_GPIO_0_RISING_SHIFT 1
+#define PALMAS_INT4_EDGE_DETECT1_GPIO_0_FALLING 0x01
+#define PALMAS_INT4_EDGE_DETECT1_GPIO_0_FALLING_SHIFT 0
+
+/* Bit definitions for INT4_EDGE_DETECT2 */
+#define PALMAS_INT4_EDGE_DETECT2_GPIO_7_RISING 0x80
+#define PALMAS_INT4_EDGE_DETECT2_GPIO_7_RISING_SHIFT 7
+#define PALMAS_INT4_EDGE_DETECT2_GPIO_7_FALLING 0x40
+#define PALMAS_INT4_EDGE_DETECT2_GPIO_7_FALLING_SHIFT 6
+#define PALMAS_INT4_EDGE_DETECT2_GPIO_6_RISING 0x20
+#define PALMAS_INT4_EDGE_DETECT2_GPIO_6_RISING_SHIFT 5
+#define PALMAS_INT4_EDGE_DETECT2_GPIO_6_FALLING 0x10
+#define PALMAS_INT4_EDGE_DETECT2_GPIO_6_FALLING_SHIFT 4
+#define PALMAS_INT4_EDGE_DETECT2_GPIO_5_RISING 0x08
+#define PALMAS_INT4_EDGE_DETECT2_GPIO_5_RISING_SHIFT 3
+#define PALMAS_INT4_EDGE_DETECT2_GPIO_5_FALLING 0x04
+#define PALMAS_INT4_EDGE_DETECT2_GPIO_5_FALLING_SHIFT 2
+#define PALMAS_INT4_EDGE_DETECT2_GPIO_4_RISING 0x02
+#define PALMAS_INT4_EDGE_DETECT2_GPIO_4_RISING_SHIFT 1
+#define PALMAS_INT4_EDGE_DETECT2_GPIO_4_FALLING 0x01
+#define PALMAS_INT4_EDGE_DETECT2_GPIO_4_FALLING_SHIFT 0
+
+/* Bit definitions for INT_CTRL */
+#define PALMAS_INT_CTRL_INT_PENDING 0x04
+#define PALMAS_INT_CTRL_INT_PENDING_SHIFT 2
+#define PALMAS_INT_CTRL_INT_CLEAR 0x01
+#define PALMAS_INT_CTRL_INT_CLEAR_SHIFT 0
+
+/* Registers for function USB_OTG */
+#define PALMAS_USB_WAKEUP 0x3
+#define PALMAS_USB_VBUS_CTRL_SET 0x4
+#define PALMAS_USB_VBUS_CTRL_CLR 0x5
+#define PALMAS_USB_ID_CTRL_SET 0x6
+#define PALMAS_USB_ID_CTRL_CLEAR 0x7
+#define PALMAS_USB_VBUS_INT_SRC 0x8
+#define PALMAS_USB_VBUS_INT_LATCH_SET 0x9
+#define PALMAS_USB_VBUS_INT_LATCH_CLR 0xA
+#define PALMAS_USB_VBUS_INT_EN_LO_SET 0xB
+#define PALMAS_USB_VBUS_INT_EN_LO_CLR 0xC
+#define PALMAS_USB_VBUS_INT_EN_HI_SET 0xD
+#define PALMAS_USB_VBUS_INT_EN_HI_CLR 0xE
+#define PALMAS_USB_ID_INT_SRC 0xF
+#define PALMAS_USB_ID_INT_LATCH_SET 0x10
+#define PALMAS_USB_ID_INT_LATCH_CLR 0x11
+#define PALMAS_USB_ID_INT_EN_LO_SET 0x12
+#define PALMAS_USB_ID_INT_EN_LO_CLR 0x13
+#define PALMAS_USB_ID_INT_EN_HI_SET 0x14
+#define PALMAS_USB_ID_INT_EN_HI_CLR 0x15
+#define PALMAS_USB_OTG_ADP_CTRL 0x16
+#define PALMAS_USB_OTG_ADP_HIGH 0x17
+#define PALMAS_USB_OTG_ADP_LOW 0x18
+#define PALMAS_USB_OTG_ADP_RISE 0x19
+#define PALMAS_USB_OTG_REVISION 0x1A
+
+/* Bit definitions for USB_WAKEUP */
+#define PALMAS_USB_WAKEUP_ID_WK_UP_COMP 0x01
+#define PALMAS_USB_WAKEUP_ID_WK_UP_COMP_SHIFT 0
+
+/* Bit definitions for USB_VBUS_CTRL_SET */
+#define PALMAS_USB_VBUS_CTRL_SET_VBUS_CHRG_VSYS 0x80
+#define PALMAS_USB_VBUS_CTRL_SET_VBUS_CHRG_VSYS_SHIFT 7
+#define PALMAS_USB_VBUS_CTRL_SET_VBUS_DISCHRG 0x20
+#define PALMAS_USB_VBUS_CTRL_SET_VBUS_DISCHRG_SHIFT 5
+#define PALMAS_USB_VBUS_CTRL_SET_VBUS_IADP_SRC 0x10
+#define PALMAS_USB_VBUS_CTRL_SET_VBUS_IADP_SRC_SHIFT 4
+#define PALMAS_USB_VBUS_CTRL_SET_VBUS_IADP_SINK 0x08
+#define PALMAS_USB_VBUS_CTRL_SET_VBUS_IADP_SINK_SHIFT 3
+#define PALMAS_USB_VBUS_CTRL_SET_VBUS_ACT_COMP 0x04
+#define PALMAS_USB_VBUS_CTRL_SET_VBUS_ACT_COMP_SHIFT 2
+
+/* Bit definitions for USB_VBUS_CTRL_CLR */
+#define PALMAS_USB_VBUS_CTRL_CLR_VBUS_CHRG_VSYS 0x80
+#define PALMAS_USB_VBUS_CTRL_CLR_VBUS_CHRG_VSYS_SHIFT 7
+#define PALMAS_USB_VBUS_CTRL_CLR_VBUS_DISCHRG 0x20
+#define PALMAS_USB_VBUS_CTRL_CLR_VBUS_DISCHRG_SHIFT 5
+#define PALMAS_USB_VBUS_CTRL_CLR_VBUS_IADP_SRC 0x10
+#define PALMAS_USB_VBUS_CTRL_CLR_VBUS_IADP_SRC_SHIFT 4
+#define PALMAS_USB_VBUS_CTRL_CLR_VBUS_IADP_SINK 0x08
+#define PALMAS_USB_VBUS_CTRL_CLR_VBUS_IADP_SINK_SHIFT 3
+#define PALMAS_USB_VBUS_CTRL_CLR_VBUS_ACT_COMP 0x04
+#define PALMAS_USB_VBUS_CTRL_CLR_VBUS_ACT_COMP_SHIFT 2
+
+/* Bit definitions for USB_ID_CTRL_SET */
+#define PALMAS_USB_ID_CTRL_SET_ID_PU_220K 0x80
+#define PALMAS_USB_ID_CTRL_SET_ID_PU_220K_SHIFT 7
+#define PALMAS_USB_ID_CTRL_SET_ID_PU_100K 0x40
+#define PALMAS_USB_ID_CTRL_SET_ID_PU_100K_SHIFT 6
+#define PALMAS_USB_ID_CTRL_SET_ID_GND_DRV 0x20
+#define PALMAS_USB_ID_CTRL_SET_ID_GND_DRV_SHIFT 5
+#define PALMAS_USB_ID_CTRL_SET_ID_SRC_16U 0x10
+#define PALMAS_USB_ID_CTRL_SET_ID_SRC_16U_SHIFT 4
+#define PALMAS_USB_ID_CTRL_SET_ID_SRC_5U 0x08
+#define PALMAS_USB_ID_CTRL_SET_ID_SRC_5U_SHIFT 3
+#define PALMAS_USB_ID_CTRL_SET_ID_ACT_COMP 0x04
+#define PALMAS_USB_ID_CTRL_SET_ID_ACT_COMP_SHIFT 2
+
+/* Bit definitions for USB_ID_CTRL_CLEAR */
+#define PALMAS_USB_ID_CTRL_CLEAR_ID_PU_220K 0x80
+#define PALMAS_USB_ID_CTRL_CLEAR_ID_PU_220K_SHIFT 7
+#define PALMAS_USB_ID_CTRL_CLEAR_ID_PU_100K 0x40
+#define PALMAS_USB_ID_CTRL_CLEAR_ID_PU_100K_SHIFT 6
+#define PALMAS_USB_ID_CTRL_CLEAR_ID_GND_DRV 0x20
+#define PALMAS_USB_ID_CTRL_CLEAR_ID_GND_DRV_SHIFT 5
+#define PALMAS_USB_ID_CTRL_CLEAR_ID_SRC_16U 0x10
+#define PALMAS_USB_ID_CTRL_CLEAR_ID_SRC_16U_SHIFT 4
+#define PALMAS_USB_ID_CTRL_CLEAR_ID_SRC_5U 0x08
+#define PALMAS_USB_ID_CTRL_CLEAR_ID_SRC_5U_SHIFT 3
+#define PALMAS_USB_ID_CTRL_CLEAR_ID_ACT_COMP 0x04
+#define PALMAS_USB_ID_CTRL_CLEAR_ID_ACT_COMP_SHIFT 2
+
+/* Bit definitions for USB_VBUS_INT_SRC */
+#define PALMAS_USB_VBUS_INT_SRC_VOTG_SESS_VLD 0x80
+#define PALMAS_USB_VBUS_INT_SRC_VOTG_SESS_VLD_SHIFT 7
+#define PALMAS_USB_VBUS_INT_SRC_VADP_PRB 0x40
+#define PALMAS_USB_VBUS_INT_SRC_VADP_PRB_SHIFT 6
+#define PALMAS_USB_VBUS_INT_SRC_VADP_SNS 0x20
+#define PALMAS_USB_VBUS_INT_SRC_VADP_SNS_SHIFT 5
+#define PALMAS_USB_VBUS_INT_SRC_VA_VBUS_VLD 0x08
+#define PALMAS_USB_VBUS_INT_SRC_VA_VBUS_VLD_SHIFT 3
+#define PALMAS_USB_VBUS_INT_SRC_VA_SESS_VLD 0x04
+#define PALMAS_USB_VBUS_INT_SRC_VA_SESS_VLD_SHIFT 2
+#define PALMAS_USB_VBUS_INT_SRC_VB_SESS_VLD 0x02
+#define PALMAS_USB_VBUS_INT_SRC_VB_SESS_VLD_SHIFT 1
+#define PALMAS_USB_VBUS_INT_SRC_VB_SESS_END 0x01
+#define PALMAS_USB_VBUS_INT_SRC_VB_SESS_END_SHIFT 0
+
+/* Bit definitions for USB_VBUS_INT_LATCH_SET */
+#define PALMAS_USB_VBUS_INT_LATCH_SET_VOTG_SESS_VLD 0x80
+#define PALMAS_USB_VBUS_INT_LATCH_SET_VOTG_SESS_VLD_SHIFT 7
+#define PALMAS_USB_VBUS_INT_LATCH_SET_VADP_PRB 0x40
+#define PALMAS_USB_VBUS_INT_LATCH_SET_VADP_PRB_SHIFT 6
+#define PALMAS_USB_VBUS_INT_LATCH_SET_VADP_SNS 0x20
+#define PALMAS_USB_VBUS_INT_LATCH_SET_VADP_SNS_SHIFT 5
+#define PALMAS_USB_VBUS_INT_LATCH_SET_ADP 0x10
+#define PALMAS_USB_VBUS_INT_LATCH_SET_ADP_SHIFT 4
+#define PALMAS_USB_VBUS_INT_LATCH_SET_VA_VBUS_VLD 0x08
+#define PALMAS_USB_VBUS_INT_LATCH_SET_VA_VBUS_VLD_SHIFT 3
+#define PALMAS_USB_VBUS_INT_LATCH_SET_VA_SESS_VLD 0x04
+#define PALMAS_USB_VBUS_INT_LATCH_SET_VA_SESS_VLD_SHIFT 2
+#define PALMAS_USB_VBUS_INT_LATCH_SET_VB_SESS_VLD 0x02
+#define PALMAS_USB_VBUS_INT_LATCH_SET_VB_SESS_VLD_SHIFT 1
+#define PALMAS_USB_VBUS_INT_LATCH_SET_VB_SESS_END 0x01
+#define PALMAS_USB_VBUS_INT_LATCH_SET_VB_SESS_END_SHIFT 0
+
+/* Bit definitions for USB_VBUS_INT_LATCH_CLR */
+#define PALMAS_USB_VBUS_INT_LATCH_CLR_VOTG_SESS_VLD 0x80
+#define PALMAS_USB_VBUS_INT_LATCH_CLR_VOTG_SESS_VLD_SHIFT 7
+#define PALMAS_USB_VBUS_INT_LATCH_CLR_VADP_PRB 0x40
+#define PALMAS_USB_VBUS_INT_LATCH_CLR_VADP_PRB_SHIFT 6
+#define PALMAS_USB_VBUS_INT_LATCH_CLR_VADP_SNS 0x20
+#define PALMAS_USB_VBUS_INT_LATCH_CLR_VADP_SNS_SHIFT 5
+#define PALMAS_USB_VBUS_INT_LATCH_CLR_ADP 0x10
+#define PALMAS_USB_VBUS_INT_LATCH_CLR_ADP_SHIFT 4
+#define PALMAS_USB_VBUS_INT_LATCH_CLR_VA_VBUS_VLD 0x08
+#define PALMAS_USB_VBUS_INT_LATCH_CLR_VA_VBUS_VLD_SHIFT 3
+#define PALMAS_USB_VBUS_INT_LATCH_CLR_VA_SESS_VLD 0x04
+#define PALMAS_USB_VBUS_INT_LATCH_CLR_VA_SESS_VLD_SHIFT 2
+#define PALMAS_USB_VBUS_INT_LATCH_CLR_VB_SESS_VLD 0x02
+#define PALMAS_USB_VBUS_INT_LATCH_CLR_VB_SESS_VLD_SHIFT 1
+#define PALMAS_USB_VBUS_INT_LATCH_CLR_VB_SESS_END 0x01
+#define PALMAS_USB_VBUS_INT_LATCH_CLR_VB_SESS_END_SHIFT 0
+
+/* Bit definitions for USB_VBUS_INT_EN_LO_SET */
+#define PALMAS_USB_VBUS_INT_EN_LO_SET_VOTG_SESS_VLD 0x80
+#define PALMAS_USB_VBUS_INT_EN_LO_SET_VOTG_SESS_VLD_SHIFT 7
+#define PALMAS_USB_VBUS_INT_EN_LO_SET_VADP_PRB 0x40
+#define PALMAS_USB_VBUS_INT_EN_LO_SET_VADP_PRB_SHIFT 6
+#define PALMAS_USB_VBUS_INT_EN_LO_SET_VADP_SNS 0x20
+#define PALMAS_USB_VBUS_INT_EN_LO_SET_VADP_SNS_SHIFT 5
+#define PALMAS_USB_VBUS_INT_EN_LO_SET_VA_VBUS_VLD 0x08
+#define PALMAS_USB_VBUS_INT_EN_LO_SET_VA_VBUS_VLD_SHIFT 3
+#define PALMAS_USB_VBUS_INT_EN_LO_SET_VA_SESS_VLD 0x04
+#define PALMAS_USB_VBUS_INT_EN_LO_SET_VA_SESS_VLD_SHIFT 2
+#define PALMAS_USB_VBUS_INT_EN_LO_SET_VB_SESS_VLD 0x02
+#define PALMAS_USB_VBUS_INT_EN_LO_SET_VB_SESS_VLD_SHIFT 1
+#define PALMAS_USB_VBUS_INT_EN_LO_SET_VB_SESS_END 0x01
+#define PALMAS_USB_VBUS_INT_EN_LO_SET_VB_SESS_END_SHIFT 0
+
+/* Bit definitions for USB_VBUS_INT_EN_LO_CLR */
+#define PALMAS_USB_VBUS_INT_EN_LO_CLR_VOTG_SESS_VLD 0x80
+#define PALMAS_USB_VBUS_INT_EN_LO_CLR_VOTG_SESS_VLD_SHIFT 7
+#define PALMAS_USB_VBUS_INT_EN_LO_CLR_VADP_PRB 0x40
+#define PALMAS_USB_VBUS_INT_EN_LO_CLR_VADP_PRB_SHIFT 6
+#define PALMAS_USB_VBUS_INT_EN_LO_CLR_VADP_SNS 0x20
+#define PALMAS_USB_VBUS_INT_EN_LO_CLR_VADP_SNS_SHIFT 5
+#define PALMAS_USB_VBUS_INT_EN_LO_CLR_VA_VBUS_VLD 0x08
+#define PALMAS_USB_VBUS_INT_EN_LO_CLR_VA_VBUS_VLD_SHIFT 3
+#define PALMAS_USB_VBUS_INT_EN_LO_CLR_VA_SESS_VLD 0x04
+#define PALMAS_USB_VBUS_INT_EN_LO_CLR_VA_SESS_VLD_SHIFT 2
+#define PALMAS_USB_VBUS_INT_EN_LO_CLR_VB_SESS_VLD 0x02
+#define PALMAS_USB_VBUS_INT_EN_LO_CLR_VB_SESS_VLD_SHIFT 1
+#define PALMAS_USB_VBUS_INT_EN_LO_CLR_VB_SESS_END 0x01
+#define PALMAS_USB_VBUS_INT_EN_LO_CLR_VB_SESS_END_SHIFT 0
+
+/* Bit definitions for USB_VBUS_INT_EN_HI_SET */
+#define PALMAS_USB_VBUS_INT_EN_HI_SET_VOTG_SESS_VLD 0x80
+#define PALMAS_USB_VBUS_INT_EN_HI_SET_VOTG_SESS_VLD_SHIFT 7
+#define PALMAS_USB_VBUS_INT_EN_HI_SET_VADP_PRB 0x40
+#define PALMAS_USB_VBUS_INT_EN_HI_SET_VADP_PRB_SHIFT 6
+#define PALMAS_USB_VBUS_INT_EN_HI_SET_VADP_SNS 0x20
+#define PALMAS_USB_VBUS_INT_EN_HI_SET_VADP_SNS_SHIFT 5
+#define PALMAS_USB_VBUS_INT_EN_HI_SET_ADP 0x10
+#define PALMAS_USB_VBUS_INT_EN_HI_SET_ADP_SHIFT 4
+#define PALMAS_USB_VBUS_INT_EN_HI_SET_VA_VBUS_VLD 0x08
+#define PALMAS_USB_VBUS_INT_EN_HI_SET_VA_VBUS_VLD_SHIFT 3
+#define PALMAS_USB_VBUS_INT_EN_HI_SET_VA_SESS_VLD 0x04
+#define PALMAS_USB_VBUS_INT_EN_HI_SET_VA_SESS_VLD_SHIFT 2
+#define PALMAS_USB_VBUS_INT_EN_HI_SET_VB_SESS_VLD 0x02
+#define PALMAS_USB_VBUS_INT_EN_HI_SET_VB_SESS_VLD_SHIFT 1
+#define PALMAS_USB_VBUS_INT_EN_HI_SET_VB_SESS_END 0x01
+#define PALMAS_USB_VBUS_INT_EN_HI_SET_VB_SESS_END_SHIFT 0
+
+/* Bit definitions for USB_VBUS_INT_EN_HI_CLR */
+#define PALMAS_USB_VBUS_INT_EN_HI_CLR_VOTG_SESS_VLD 0x80
+#define PALMAS_USB_VBUS_INT_EN_HI_CLR_VOTG_SESS_VLD_SHIFT 7
+#define PALMAS_USB_VBUS_INT_EN_HI_CLR_VADP_PRB 0x40
+#define PALMAS_USB_VBUS_INT_EN_HI_CLR_VADP_PRB_SHIFT 6
+#define PALMAS_USB_VBUS_INT_EN_HI_CLR_VADP_SNS 0x20
+#define PALMAS_USB_VBUS_INT_EN_HI_CLR_VADP_SNS_SHIFT 5
+#define PALMAS_USB_VBUS_INT_EN_HI_CLR_ADP 0x10
+#define PALMAS_USB_VBUS_INT_EN_HI_CLR_ADP_SHIFT 4
+#define PALMAS_USB_VBUS_INT_EN_HI_CLR_VA_VBUS_VLD 0x08
+#define PALMAS_USB_VBUS_INT_EN_HI_CLR_VA_VBUS_VLD_SHIFT 3
+#define PALMAS_USB_VBUS_INT_EN_HI_CLR_VA_SESS_VLD 0x04
+#define PALMAS_USB_VBUS_INT_EN_HI_CLR_VA_SESS_VLD_SHIFT 2
+#define PALMAS_USB_VBUS_INT_EN_HI_CLR_VB_SESS_VLD 0x02
+#define PALMAS_USB_VBUS_INT_EN_HI_CLR_VB_SESS_VLD_SHIFT 1
+#define PALMAS_USB_VBUS_INT_EN_HI_CLR_VB_SESS_END 0x01
+#define PALMAS_USB_VBUS_INT_EN_HI_CLR_VB_SESS_END_SHIFT 0
+
+/* Bit definitions for USB_ID_INT_SRC */
+#define PALMAS_USB_ID_INT_SRC_ID_FLOAT 0x10
+#define PALMAS_USB_ID_INT_SRC_ID_FLOAT_SHIFT 4
+#define PALMAS_USB_ID_INT_SRC_ID_A 0x08
+#define PALMAS_USB_ID_INT_SRC_ID_A_SHIFT 3
+#define PALMAS_USB_ID_INT_SRC_ID_B 0x04
+#define PALMAS_USB_ID_INT_SRC_ID_B_SHIFT 2
+#define PALMAS_USB_ID_INT_SRC_ID_C 0x02
+#define PALMAS_USB_ID_INT_SRC_ID_C_SHIFT 1
+#define PALMAS_USB_ID_INT_SRC_ID_GND 0x01
+#define PALMAS_USB_ID_INT_SRC_ID_GND_SHIFT 0
+
+/* Bit definitions for USB_ID_INT_LATCH_SET */
+#define PALMAS_USB_ID_INT_LATCH_SET_ID_FLOAT 0x10
+#define PALMAS_USB_ID_INT_LATCH_SET_ID_FLOAT_SHIFT 4
+#define PALMAS_USB_ID_INT_LATCH_SET_ID_A 0x08
+#define PALMAS_USB_ID_INT_LATCH_SET_ID_A_SHIFT 3
+#define PALMAS_USB_ID_INT_LATCH_SET_ID_B 0x04
+#define PALMAS_USB_ID_INT_LATCH_SET_ID_B_SHIFT 2
+#define PALMAS_USB_ID_INT_LATCH_SET_ID_C 0x02
+#define PALMAS_USB_ID_INT_LATCH_SET_ID_C_SHIFT 1
+#define PALMAS_USB_ID_INT_LATCH_SET_ID_GND 0x01
+#define PALMAS_USB_ID_INT_LATCH_SET_ID_GND_SHIFT 0
+
+/* Bit definitions for USB_ID_INT_LATCH_CLR */
+#define PALMAS_USB_ID_INT_LATCH_CLR_ID_FLOAT 0x10
+#define PALMAS_USB_ID_INT_LATCH_CLR_ID_FLOAT_SHIFT 4
+#define PALMAS_USB_ID_INT_LATCH_CLR_ID_A 0x08
+#define PALMAS_USB_ID_INT_LATCH_CLR_ID_A_SHIFT 3
+#define PALMAS_USB_ID_INT_LATCH_CLR_ID_B 0x04
+#define PALMAS_USB_ID_INT_LATCH_CLR_ID_B_SHIFT 2
+#define PALMAS_USB_ID_INT_LATCH_CLR_ID_C 0x02
+#define PALMAS_USB_ID_INT_LATCH_CLR_ID_C_SHIFT 1
+#define PALMAS_USB_ID_INT_LATCH_CLR_ID_GND 0x01
+#define PALMAS_USB_ID_INT_LATCH_CLR_ID_GND_SHIFT 0
+
+/* Bit definitions for USB_ID_INT_EN_LO_SET */
+#define PALMAS_USB_ID_INT_EN_LO_SET_ID_FLOAT 0x10
+#define PALMAS_USB_ID_INT_EN_LO_SET_ID_FLOAT_SHIFT 4
+#define PALMAS_USB_ID_INT_EN_LO_SET_ID_A 0x08
+#define PALMAS_USB_ID_INT_EN_LO_SET_ID_A_SHIFT 3
+#define PALMAS_USB_ID_INT_EN_LO_SET_ID_B 0x04
+#define PALMAS_USB_ID_INT_EN_LO_SET_ID_B_SHIFT 2
+#define PALMAS_USB_ID_INT_EN_LO_SET_ID_C 0x02
+#define PALMAS_USB_ID_INT_EN_LO_SET_ID_C_SHIFT 1
+#define PALMAS_USB_ID_INT_EN_LO_SET_ID_GND 0x01
+#define PALMAS_USB_ID_INT_EN_LO_SET_ID_GND_SHIFT 0
+
+/* Bit definitions for USB_ID_INT_EN_LO_CLR */
+#define PALMAS_USB_ID_INT_EN_LO_CLR_ID_FLOAT 0x10
+#define PALMAS_USB_ID_INT_EN_LO_CLR_ID_FLOAT_SHIFT 4
+#define PALMAS_USB_ID_INT_EN_LO_CLR_ID_A 0x08
+#define PALMAS_USB_ID_INT_EN_LO_CLR_ID_A_SHIFT 3
+#define PALMAS_USB_ID_INT_EN_LO_CLR_ID_B 0x04
+#define PALMAS_USB_ID_INT_EN_LO_CLR_ID_B_SHIFT 2
+#define PALMAS_USB_ID_INT_EN_LO_CLR_ID_C 0x02
+#define PALMAS_USB_ID_INT_EN_LO_CLR_ID_C_SHIFT 1
+#define PALMAS_USB_ID_INT_EN_LO_CLR_ID_GND 0x01
+#define PALMAS_USB_ID_INT_EN_LO_CLR_ID_GND_SHIFT 0
+
+/* Bit definitions for USB_ID_INT_EN_HI_SET */
+#define PALMAS_USB_ID_INT_EN_HI_SET_ID_FLOAT 0x10
+#define PALMAS_USB_ID_INT_EN_HI_SET_ID_FLOAT_SHIFT 4
+#define PALMAS_USB_ID_INT_EN_HI_SET_ID_A 0x08
+#define PALMAS_USB_ID_INT_EN_HI_SET_ID_A_SHIFT 3
+#define PALMAS_USB_ID_INT_EN_HI_SET_ID_B 0x04
+#define PALMAS_USB_ID_INT_EN_HI_SET_ID_B_SHIFT 2
+#define PALMAS_USB_ID_INT_EN_HI_SET_ID_C 0x02
+#define PALMAS_USB_ID_INT_EN_HI_SET_ID_C_SHIFT 1
+#define PALMAS_USB_ID_INT_EN_HI_SET_ID_GND 0x01
+#define PALMAS_USB_ID_INT_EN_HI_SET_ID_GND_SHIFT 0
+
+/* Bit definitions for USB_ID_INT_EN_HI_CLR */
+#define PALMAS_USB_ID_INT_EN_HI_CLR_ID_FLOAT 0x10
+#define PALMAS_USB_ID_INT_EN_HI_CLR_ID_FLOAT_SHIFT 4
+#define PALMAS_USB_ID_INT_EN_HI_CLR_ID_A 0x08
+#define PALMAS_USB_ID_INT_EN_HI_CLR_ID_A_SHIFT 3
+#define PALMAS_USB_ID_INT_EN_HI_CLR_ID_B 0x04
+#define PALMAS_USB_ID_INT_EN_HI_CLR_ID_B_SHIFT 2
+#define PALMAS_USB_ID_INT_EN_HI_CLR_ID_C 0x02
+#define PALMAS_USB_ID_INT_EN_HI_CLR_ID_C_SHIFT 1
+#define PALMAS_USB_ID_INT_EN_HI_CLR_ID_GND 0x01
+#define PALMAS_USB_ID_INT_EN_HI_CLR_ID_GND_SHIFT 0
+
+/* Bit definitions for USB_OTG_ADP_CTRL */
+#define PALMAS_USB_OTG_ADP_CTRL_ADP_EN 0x04
+#define PALMAS_USB_OTG_ADP_CTRL_ADP_EN_SHIFT 2
+#define PALMAS_USB_OTG_ADP_CTRL_ADP_MODE_MASK 0x03
+#define PALMAS_USB_OTG_ADP_CTRL_ADP_MODE_SHIFT 0
+
+/* Bit definitions for USB_OTG_ADP_HIGH */
+#define PALMAS_USB_OTG_ADP_HIGH_T_ADP_HIGH_MASK 0xff
+#define PALMAS_USB_OTG_ADP_HIGH_T_ADP_HIGH_SHIFT 0
+
+/* Bit definitions for USB_OTG_ADP_LOW */
+#define PALMAS_USB_OTG_ADP_LOW_T_ADP_LOW_MASK 0xff
+#define PALMAS_USB_OTG_ADP_LOW_T_ADP_LOW_SHIFT 0
+
+/* Bit definitions for USB_OTG_ADP_RISE */
+#define PALMAS_USB_OTG_ADP_RISE_T_ADP_RISE_MASK 0xff
+#define PALMAS_USB_OTG_ADP_RISE_T_ADP_RISE_SHIFT 0
+
+/* Bit definitions for USB_OTG_REVISION */
+#define PALMAS_USB_OTG_REVISION_OTG_REV 0x01
+#define PALMAS_USB_OTG_REVISION_OTG_REV_SHIFT 0
+
+/* Registers for function VIBRATOR */
+#define PALMAS_VIBRA_CTRL 0x0
+
+/* Bit definitions for VIBRA_CTRL */
+#define PALMAS_VIBRA_CTRL_PWM_DUTY_SEL_MASK 0x06
+#define PALMAS_VIBRA_CTRL_PWM_DUTY_SEL_SHIFT 1
+#define PALMAS_VIBRA_CTRL_PWM_FREQ_SEL 0x01
+#define PALMAS_VIBRA_CTRL_PWM_FREQ_SEL_SHIFT 0
+
+/* Registers for function GPIO */
+#define PALMAS_GPIO_DATA_IN 0x0
+#define PALMAS_GPIO_DATA_DIR 0x1
+#define PALMAS_GPIO_DATA_OUT 0x2
+#define PALMAS_GPIO_DEBOUNCE_EN 0x3
+#define PALMAS_GPIO_CLEAR_DATA_OUT 0x4
+#define PALMAS_GPIO_SET_DATA_OUT 0x5
+#define PALMAS_PU_PD_GPIO_CTRL1 0x6
+#define PALMAS_PU_PD_GPIO_CTRL2 0x7
+#define PALMAS_OD_OUTPUT_GPIO_CTRL 0x8
+
+/* Bit definitions for GPIO_DATA_IN */
+#define PALMAS_GPIO_DATA_IN_GPIO_7_IN 0x80
+#define PALMAS_GPIO_DATA_IN_GPIO_7_IN_SHIFT 7
+#define PALMAS_GPIO_DATA_IN_GPIO_6_IN 0x40
+#define PALMAS_GPIO_DATA_IN_GPIO_6_IN_SHIFT 6
+#define PALMAS_GPIO_DATA_IN_GPIO_5_IN 0x20
+#define PALMAS_GPIO_DATA_IN_GPIO_5_IN_SHIFT 5
+#define PALMAS_GPIO_DATA_IN_GPIO_4_IN 0x10
+#define PALMAS_GPIO_DATA_IN_GPIO_4_IN_SHIFT 4
+#define PALMAS_GPIO_DATA_IN_GPIO_3_IN 0x08
+#define PALMAS_GPIO_DATA_IN_GPIO_3_IN_SHIFT 3
+#define PALMAS_GPIO_DATA_IN_GPIO_2_IN 0x04
+#define PALMAS_GPIO_DATA_IN_GPIO_2_IN_SHIFT 2
+#define PALMAS_GPIO_DATA_IN_GPIO_1_IN 0x02
+#define PALMAS_GPIO_DATA_IN_GPIO_1_IN_SHIFT 1
+#define PALMAS_GPIO_DATA_IN_GPIO_0_IN 0x01
+#define PALMAS_GPIO_DATA_IN_GPIO_0_IN_SHIFT 0
+
+/* Bit definitions for GPIO_DATA_DIR */
+#define PALMAS_GPIO_DATA_DIR_GPIO_7_DIR 0x80
+#define PALMAS_GPIO_DATA_DIR_GPIO_7_DIR_SHIFT 7
+#define PALMAS_GPIO_DATA_DIR_GPIO_6_DIR 0x40
+#define PALMAS_GPIO_DATA_DIR_GPIO_6_DIR_SHIFT 6
+#define PALMAS_GPIO_DATA_DIR_GPIO_5_DIR 0x20
+#define PALMAS_GPIO_DATA_DIR_GPIO_5_DIR_SHIFT 5
+#define PALMAS_GPIO_DATA_DIR_GPIO_4_DIR 0x10
+#define PALMAS_GPIO_DATA_DIR_GPIO_4_DIR_SHIFT 4
+#define PALMAS_GPIO_DATA_DIR_GPIO_3_DIR 0x08
+#define PALMAS_GPIO_DATA_DIR_GPIO_3_DIR_SHIFT 3
+#define PALMAS_GPIO_DATA_DIR_GPIO_2_DIR 0x04
+#define PALMAS_GPIO_DATA_DIR_GPIO_2_DIR_SHIFT 2
+#define PALMAS_GPIO_DATA_DIR_GPIO_1_DIR 0x02
+#define PALMAS_GPIO_DATA_DIR_GPIO_1_DIR_SHIFT 1
+#define PALMAS_GPIO_DATA_DIR_GPIO_0_DIR 0x01
+#define PALMAS_GPIO_DATA_DIR_GPIO_0_DIR_SHIFT 0
+
+/* Bit definitions for GPIO_DATA_OUT */
+#define PALMAS_GPIO_DATA_OUT_GPIO_7_OUT 0x80
+#define PALMAS_GPIO_DATA_OUT_GPIO_7_OUT_SHIFT 7
+#define PALMAS_GPIO_DATA_OUT_GPIO_6_OUT 0x40
+#define PALMAS_GPIO_DATA_OUT_GPIO_6_OUT_SHIFT 6
+#define PALMAS_GPIO_DATA_OUT_GPIO_5_OUT 0x20
+#define PALMAS_GPIO_DATA_OUT_GPIO_5_OUT_SHIFT 5
+#define PALMAS_GPIO_DATA_OUT_GPIO_4_OUT 0x10
+#define PALMAS_GPIO_DATA_OUT_GPIO_4_OUT_SHIFT 4
+#define PALMAS_GPIO_DATA_OUT_GPIO_3_OUT 0x08
+#define PALMAS_GPIO_DATA_OUT_GPIO_3_OUT_SHIFT 3
+#define PALMAS_GPIO_DATA_OUT_GPIO_2_OUT 0x04
+#define PALMAS_GPIO_DATA_OUT_GPIO_2_OUT_SHIFT 2
+#define PALMAS_GPIO_DATA_OUT_GPIO_1_OUT 0x02
+#define PALMAS_GPIO_DATA_OUT_GPIO_1_OUT_SHIFT 1
+#define PALMAS_GPIO_DATA_OUT_GPIO_0_OUT 0x01
+#define PALMAS_GPIO_DATA_OUT_GPIO_0_OUT_SHIFT 0
+
+/* Bit definitions for GPIO_DEBOUNCE_EN */
+#define PALMAS_GPIO_DEBOUNCE_EN_GPIO_7_DEBOUNCE_EN 0x80
+#define PALMAS_GPIO_DEBOUNCE_EN_GPIO_7_DEBOUNCE_EN_SHIFT 7
+#define PALMAS_GPIO_DEBOUNCE_EN_GPIO_6_DEBOUNCE_EN 0x40
+#define PALMAS_GPIO_DEBOUNCE_EN_GPIO_6_DEBOUNCE_EN_SHIFT 6
+#define PALMAS_GPIO_DEBOUNCE_EN_GPIO_5_DEBOUNCE_EN 0x20
+#define PALMAS_GPIO_DEBOUNCE_EN_GPIO_5_DEBOUNCE_EN_SHIFT 5
+#define PALMAS_GPIO_DEBOUNCE_EN_GPIO_4_DEBOUNCE_EN 0x10
+#define PALMAS_GPIO_DEBOUNCE_EN_GPIO_4_DEBOUNCE_EN_SHIFT 4
+#define PALMAS_GPIO_DEBOUNCE_EN_GPIO_3_DEBOUNCE_EN 0x08
+#define PALMAS_GPIO_DEBOUNCE_EN_GPIO_3_DEBOUNCE_EN_SHIFT 3
+#define PALMAS_GPIO_DEBOUNCE_EN_GPIO_2_DEBOUNCE_EN 0x04
+#define PALMAS_GPIO_DEBOUNCE_EN_GPIO_2_DEBOUNCE_EN_SHIFT 2
+#define PALMAS_GPIO_DEBOUNCE_EN_GPIO_1_DEBOUNCE_EN 0x02
+#define PALMAS_GPIO_DEBOUNCE_EN_GPIO_1_DEBOUNCE_EN_SHIFT 1
+#define PALMAS_GPIO_DEBOUNCE_EN_GPIO_0_DEBOUNCE_EN 0x01
+#define PALMAS_GPIO_DEBOUNCE_EN_GPIO_0_DEBOUNCE_EN_SHIFT 0
+
+/* Bit definitions for GPIO_CLEAR_DATA_OUT */
+#define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_7_CLEAR_DATA_OUT 0x80
+#define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_7_CLEAR_DATA_OUT_SHIFT 7
+#define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_6_CLEAR_DATA_OUT 0x40
+#define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_6_CLEAR_DATA_OUT_SHIFT 6
+#define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_5_CLEAR_DATA_OUT 0x20
+#define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_5_CLEAR_DATA_OUT_SHIFT 5
+#define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_4_CLEAR_DATA_OUT 0x10
+#define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_4_CLEAR_DATA_OUT_SHIFT 4
+#define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_3_CLEAR_DATA_OUT 0x08
+#define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_3_CLEAR_DATA_OUT_SHIFT 3
+#define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_2_CLEAR_DATA_OUT 0x04
+#define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_2_CLEAR_DATA_OUT_SHIFT 2
+#define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_1_CLEAR_DATA_OUT 0x02
+#define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_1_CLEAR_DATA_OUT_SHIFT 1
+#define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_0_CLEAR_DATA_OUT 0x01
+#define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_0_CLEAR_DATA_OUT_SHIFT 0
+
+/* Bit definitions for GPIO_SET_DATA_OUT */
+#define PALMAS_GPIO_SET_DATA_OUT_GPIO_7_SET_DATA_OUT 0x80
+#define PALMAS_GPIO_SET_DATA_OUT_GPIO_7_SET_DATA_OUT_SHIFT 7
+#define PALMAS_GPIO_SET_DATA_OUT_GPIO_6_SET_DATA_OUT 0x40
+#define PALMAS_GPIO_SET_DATA_OUT_GPIO_6_SET_DATA_OUT_SHIFT 6
+#define PALMAS_GPIO_SET_DATA_OUT_GPIO_5_SET_DATA_OUT 0x20
+#define PALMAS_GPIO_SET_DATA_OUT_GPIO_5_SET_DATA_OUT_SHIFT 5
+#define PALMAS_GPIO_SET_DATA_OUT_GPIO_4_SET_DATA_OUT 0x10
+#define PALMAS_GPIO_SET_DATA_OUT_GPIO_4_SET_DATA_OUT_SHIFT 4
+#define PALMAS_GPIO_SET_DATA_OUT_GPIO_3_SET_DATA_OUT 0x08
+#define PALMAS_GPIO_SET_DATA_OUT_GPIO_3_SET_DATA_OUT_SHIFT 3
+#define PALMAS_GPIO_SET_DATA_OUT_GPIO_2_SET_DATA_OUT 0x04
+#define PALMAS_GPIO_SET_DATA_OUT_GPIO_2_SET_DATA_OUT_SHIFT 2
+#define PALMAS_GPIO_SET_DATA_OUT_GPIO_1_SET_DATA_OUT 0x02
+#define PALMAS_GPIO_SET_DATA_OUT_GPIO_1_SET_DATA_OUT_SHIFT 1
+#define PALMAS_GPIO_SET_DATA_OUT_GPIO_0_SET_DATA_OUT 0x01
+#define PALMAS_GPIO_SET_DATA_OUT_GPIO_0_SET_DATA_OUT_SHIFT 0
+
+/* Bit definitions for PU_PD_GPIO_CTRL1 */
+#define PALMAS_PU_PD_GPIO_CTRL1_GPIO_3_PD 0x40
+#define PALMAS_PU_PD_GPIO_CTRL1_GPIO_3_PD_SHIFT 6
+#define PALMAS_PU_PD_GPIO_CTRL1_GPIO_2_PU 0x20
+#define PALMAS_PU_PD_GPIO_CTRL1_GPIO_2_PU_SHIFT 5
+#define PALMAS_PU_PD_GPIO_CTRL1_GPIO_2_PD 0x10
+#define PALMAS_PU_PD_GPIO_CTRL1_GPIO_2_PD_SHIFT 4
+#define PALMAS_PU_PD_GPIO_CTRL1_GPIO_1_PU 0x08
+#define PALMAS_PU_PD_GPIO_CTRL1_GPIO_1_PU_SHIFT 3
+#define PALMAS_PU_PD_GPIO_CTRL1_GPIO_1_PD 0x04
+#define PALMAS_PU_PD_GPIO_CTRL1_GPIO_1_PD_SHIFT 2
+#define PALMAS_PU_PD_GPIO_CTRL1_GPIO_0_PD 0x01
+#define PALMAS_PU_PD_GPIO_CTRL1_GPIO_0_PD_SHIFT 0
+
+/* Bit definitions for PU_PD_GPIO_CTRL2 */
+#define PALMAS_PU_PD_GPIO_CTRL2_GPIO_7_PD 0x40
+#define PALMAS_PU_PD_GPIO_CTRL2_GPIO_7_PD_SHIFT 6
+#define PALMAS_PU_PD_GPIO_CTRL2_GPIO_6_PU 0x20
+#define PALMAS_PU_PD_GPIO_CTRL2_GPIO_6_PU_SHIFT 5
+#define PALMAS_PU_PD_GPIO_CTRL2_GPIO_6_PD 0x10
+#define PALMAS_PU_PD_GPIO_CTRL2_GPIO_6_PD_SHIFT 4
+#define PALMAS_PU_PD_GPIO_CTRL2_GPIO_5_PU 0x08
+#define PALMAS_PU_PD_GPIO_CTRL2_GPIO_5_PU_SHIFT 3
+#define PALMAS_PU_PD_GPIO_CTRL2_GPIO_5_PD 0x04
+#define PALMAS_PU_PD_GPIO_CTRL2_GPIO_5_PD_SHIFT 2
+#define PALMAS_PU_PD_GPIO_CTRL2_GPIO_4_PU 0x02
+#define PALMAS_PU_PD_GPIO_CTRL2_GPIO_4_PU_SHIFT 1
+#define PALMAS_PU_PD_GPIO_CTRL2_GPIO_4_PD 0x01
+#define PALMAS_PU_PD_GPIO_CTRL2_GPIO_4_PD_SHIFT 0
+
+/* Bit definitions for OD_OUTPUT_GPIO_CTRL */
+#define PALMAS_OD_OUTPUT_GPIO_CTRL_GPIO_5_OD 0x20
+#define PALMAS_OD_OUTPUT_GPIO_CTRL_GPIO_5_OD_SHIFT 5
+#define PALMAS_OD_OUTPUT_GPIO_CTRL_GPIO_2_OD 0x04
+#define PALMAS_OD_OUTPUT_GPIO_CTRL_GPIO_2_OD_SHIFT 2
+#define PALMAS_OD_OUTPUT_GPIO_CTRL_GPIO_1_OD 0x02
+#define PALMAS_OD_OUTPUT_GPIO_CTRL_GPIO_1_OD_SHIFT 1
+
+/* Registers for function GPADC */
+#define PALMAS_GPADC_CTRL1 0x0
+#define PALMAS_GPADC_CTRL2 0x1
+#define PALMAS_GPADC_RT_CTRL 0x2
+#define PALMAS_GPADC_AUTO_CTRL 0x3
+#define PALMAS_GPADC_STATUS 0x4
+#define PALMAS_GPADC_RT_SELECT 0x5
+#define PALMAS_GPADC_RT_CONV0_LSB 0x6
+#define PALMAS_GPADC_RT_CONV0_MSB 0x7
+#define PALMAS_GPADC_AUTO_SELECT 0x8
+#define PALMAS_GPADC_AUTO_CONV0_LSB 0x9
+#define PALMAS_GPADC_AUTO_CONV0_MSB 0xA
+#define PALMAS_GPADC_AUTO_CONV1_LSB 0xB
+#define PALMAS_GPADC_AUTO_CONV1_MSB 0xC
+#define PALMAS_GPADC_SW_SELECT 0xD
+#define PALMAS_GPADC_SW_CONV0_LSB 0xE
+#define PALMAS_GPADC_SW_CONV0_MSB 0xF
+#define PALMAS_GPADC_THRES_CONV0_LSB 0x10
+#define PALMAS_GPADC_THRES_CONV0_MSB 0x11
+#define PALMAS_GPADC_THRES_CONV1_LSB 0x12
+#define PALMAS_GPADC_THRES_CONV1_MSB 0x13
+#define PALMAS_GPADC_SMPS_ILMONITOR_EN 0x14
+#define PALMAS_GPADC_SMPS_VSEL_MONITORING 0x15
+
+/* Bit definitions for GPADC_CTRL1 */
+#define PALMAS_GPADC_CTRL1_RESERVED_MASK 0xc0
+#define PALMAS_GPADC_CTRL1_RESERVED_SHIFT 6
+#define PALMAS_GPADC_CTRL1_CURRENT_SRC_CH3_MASK 0x30
+#define PALMAS_GPADC_CTRL1_CURRENT_SRC_CH3_SHIFT 4
+#define PALMAS_GPADC_CTRL1_CURRENT_SRC_CH0_MASK 0x0c
+#define PALMAS_GPADC_CTRL1_CURRENT_SRC_CH0_SHIFT 2
+#define PALMAS_GPADC_CTRL1_BAT_REMOVAL_DET 0x02
+#define PALMAS_GPADC_CTRL1_BAT_REMOVAL_DET_SHIFT 1
+#define PALMAS_GPADC_CTRL1_GPADC_FORCE 0x01
+#define PALMAS_GPADC_CTRL1_GPADC_FORCE_SHIFT 0
+
+/* Bit definitions for GPADC_CTRL2 */
+#define PALMAS_GPADC_CTRL2_RESERVED_MASK 0x06
+#define PALMAS_GPADC_CTRL2_RESERVED_SHIFT 1
+
+/* Bit definitions for GPADC_RT_CTRL */
+#define PALMAS_GPADC_RT_CTRL_EXTEND_DELAY 0x02
+#define PALMAS_GPADC_RT_CTRL_EXTEND_DELAY_SHIFT 1
+#define PALMAS_GPADC_RT_CTRL_START_POLARITY 0x01
+#define PALMAS_GPADC_RT_CTRL_START_POLARITY_SHIFT 0
+
+/* Bit definitions for GPADC_AUTO_CTRL */
+#define PALMAS_GPADC_AUTO_CTRL_SHUTDOWN_CONV1 0x80
+#define PALMAS_GPADC_AUTO_CTRL_SHUTDOWN_CONV1_SHIFT 7
+#define PALMAS_GPADC_AUTO_CTRL_SHUTDOWN_CONV0 0x40
+#define PALMAS_GPADC_AUTO_CTRL_SHUTDOWN_CONV0_SHIFT 6
+#define PALMAS_GPADC_AUTO_CTRL_AUTO_CONV1_EN 0x20
+#define PALMAS_GPADC_AUTO_CTRL_AUTO_CONV1_EN_SHIFT 5
+#define PALMAS_GPADC_AUTO_CTRL_AUTO_CONV0_EN 0x10
+#define PALMAS_GPADC_AUTO_CTRL_AUTO_CONV0_EN_SHIFT 4
+#define PALMAS_GPADC_AUTO_CTRL_COUNTER_CONV_MASK 0x0f
+#define PALMAS_GPADC_AUTO_CTRL_COUNTER_CONV_SHIFT 0
+
+/* Bit definitions for GPADC_STATUS */
+#define PALMAS_GPADC_STATUS_GPADC_AVAILABLE 0x10
+#define PALMAS_GPADC_STATUS_GPADC_AVAILABLE_SHIFT 4
+
+/* Bit definitions for GPADC_RT_SELECT */
+#define PALMAS_GPADC_RT_SELECT_RT_CONV_EN 0x80
+#define PALMAS_GPADC_RT_SELECT_RT_CONV_EN_SHIFT 7
+#define PALMAS_GPADC_RT_SELECT_RT_CONV0_SEL_MASK 0x0f
+#define PALMAS_GPADC_RT_SELECT_RT_CONV0_SEL_SHIFT 0
+
+/* Bit definitions for GPADC_RT_CONV0_LSB */
+#define PALMAS_GPADC_RT_CONV0_LSB_RT_CONV0_LSB_MASK 0xff
+#define PALMAS_GPADC_RT_CONV0_LSB_RT_CONV0_LSB_SHIFT 0
+
+/* Bit definitions for GPADC_RT_CONV0_MSB */
+#define PALMAS_GPADC_RT_CONV0_MSB_RT_CONV0_MSB_MASK 0x0f
+#define PALMAS_GPADC_RT_CONV0_MSB_RT_CONV0_MSB_SHIFT 0
+
+/* Bit definitions for GPADC_AUTO_SELECT */
+#define PALMAS_GPADC_AUTO_SELECT_AUTO_CONV1_SEL_MASK 0xf0
+#define PALMAS_GPADC_AUTO_SELECT_AUTO_CONV1_SEL_SHIFT 4
+#define PALMAS_GPADC_AUTO_SELECT_AUTO_CONV0_SEL_MASK 0x0f
+#define PALMAS_GPADC_AUTO_SELECT_AUTO_CONV0_SEL_SHIFT 0
+
+/* Bit definitions for GPADC_AUTO_CONV0_LSB */
+#define PALMAS_GPADC_AUTO_CONV0_LSB_AUTO_CONV0_LSB_MASK 0xff
+#define PALMAS_GPADC_AUTO_CONV0_LSB_AUTO_CONV0_LSB_SHIFT 0
+
+/* Bit definitions for GPADC_AUTO_CONV0_MSB */
+#define PALMAS_GPADC_AUTO_CONV0_MSB_AUTO_CONV0_MSB_MASK 0x0f
+#define PALMAS_GPADC_AUTO_CONV0_MSB_AUTO_CONV0_MSB_SHIFT 0
+
+/* Bit definitions for GPADC_AUTO_CONV1_LSB */
+#define PALMAS_GPADC_AUTO_CONV1_LSB_AUTO_CONV1_LSB_MASK 0xff
+#define PALMAS_GPADC_AUTO_CONV1_LSB_AUTO_CONV1_LSB_SHIFT 0
+
+/* Bit definitions for GPADC_AUTO_CONV1_MSB */
+#define PALMAS_GPADC_AUTO_CONV1_MSB_AUTO_CONV1_MSB_MASK 0x0f
+#define PALMAS_GPADC_AUTO_CONV1_MSB_AUTO_CONV1_MSB_SHIFT 0
+
+/* Bit definitions for GPADC_SW_SELECT */
+#define PALMAS_GPADC_SW_SELECT_SW_CONV_EN 0x80
+#define PALMAS_GPADC_SW_SELECT_SW_CONV_EN_SHIFT 7
+#define PALMAS_GPADC_SW_SELECT_SW_START_CONV0 0x10
+#define PALMAS_GPADC_SW_SELECT_SW_START_CONV0_SHIFT 4
+#define PALMAS_GPADC_SW_SELECT_SW_CONV0_SEL_MASK 0x0f
+#define PALMAS_GPADC_SW_SELECT_SW_CONV0_SEL_SHIFT 0
+
+/* Bit definitions for GPADC_SW_CONV0_LSB */
+#define PALMAS_GPADC_SW_CONV0_LSB_SW_CONV0_LSB_MASK 0xff
+#define PALMAS_GPADC_SW_CONV0_LSB_SW_CONV0_LSB_SHIFT 0
+
+/* Bit definitions for GPADC_SW_CONV0_MSB */
+#define PALMAS_GPADC_SW_CONV0_MSB_SW_CONV0_MSB_MASK 0x0f
+#define PALMAS_GPADC_SW_CONV0_MSB_SW_CONV0_MSB_SHIFT 0
+
+/* Bit definitions for GPADC_THRES_CONV0_LSB */
+#define PALMAS_GPADC_THRES_CONV0_LSB_THRES_CONV0_LSB_MASK 0xff
+#define PALMAS_GPADC_THRES_CONV0_LSB_THRES_CONV0_LSB_SHIFT 0
+
+/* Bit definitions for GPADC_THRES_CONV0_MSB */
+#define PALMAS_GPADC_THRES_CONV0_MSB_THRES_CONV0_POL 0x80
+#define PALMAS_GPADC_THRES_CONV0_MSB_THRES_CONV0_POL_SHIFT 7
+#define PALMAS_GPADC_THRES_CONV0_MSB_THRES_CONV0_MSB_MASK 0x0f
+#define PALMAS_GPADC_THRES_CONV0_MSB_THRES_CONV0_MSB_SHIFT 0
+
+/* Bit definitions for GPADC_THRES_CONV1_LSB */
+#define PALMAS_GPADC_THRES_CONV1_LSB_THRES_CONV1_LSB_MASK 0xff
+#define PALMAS_GPADC_THRES_CONV1_LSB_THRES_CONV1_LSB_SHIFT 0
+
+/* Bit definitions for GPADC_THRES_CONV1_MSB */
+#define PALMAS_GPADC_THRES_CONV1_MSB_THRES_CONV1_POL 0x80
+#define PALMAS_GPADC_THRES_CONV1_MSB_THRES_CONV1_POL_SHIFT 7
+#define PALMAS_GPADC_THRES_CONV1_MSB_THRES_CONV1_MSB_MASK 0x0f
+#define PALMAS_GPADC_THRES_CONV1_MSB_THRES_CONV1_MSB_SHIFT 0
+
+/* Bit definitions for GPADC_SMPS_ILMONITOR_EN */
+#define PALMAS_GPADC_SMPS_ILMONITOR_EN_SMPS_ILMON_EN 0x20
+#define PALMAS_GPADC_SMPS_ILMONITOR_EN_SMPS_ILMON_EN_SHIFT 5
+#define PALMAS_GPADC_SMPS_ILMONITOR_EN_SMPS_ILMON_REXT 0x10
+#define PALMAS_GPADC_SMPS_ILMONITOR_EN_SMPS_ILMON_REXT_SHIFT 4
+#define PALMAS_GPADC_SMPS_ILMONITOR_EN_SMPS_ILMON_SEL_MASK 0x0f
+#define PALMAS_GPADC_SMPS_ILMONITOR_EN_SMPS_ILMON_SEL_SHIFT 0
+
+/* Bit definitions for GPADC_SMPS_VSEL_MONITORING */
+#define PALMAS_GPADC_SMPS_VSEL_MONITORING_ACTIVE_PHASE 0x80
+#define PALMAS_GPADC_SMPS_VSEL_MONITORING_ACTIVE_PHASE_SHIFT 7
+#define PALMAS_GPADC_SMPS_VSEL_MONITORING_SMPS_VSEL_MONITORING_MASK 0x7f
+#define PALMAS_GPADC_SMPS_VSEL_MONITORING_SMPS_VSEL_MONITORING_SHIFT 0
+
+/* Registers for function GPADC */
+#define PALMAS_GPADC_TRIM1 0x0
+#define PALMAS_GPADC_TRIM2 0x1
+#define PALMAS_GPADC_TRIM3 0x2
+#define PALMAS_GPADC_TRIM4 0x3
+#define PALMAS_GPADC_TRIM5 0x4
+#define PALMAS_GPADC_TRIM6 0x5
+#define PALMAS_GPADC_TRIM7 0x6
+#define PALMAS_GPADC_TRIM8 0x7
+#define PALMAS_GPADC_TRIM9 0x8
+#define PALMAS_GPADC_TRIM10 0x9
+#define PALMAS_GPADC_TRIM11 0xA
+#define PALMAS_GPADC_TRIM12 0xB
+#define PALMAS_GPADC_TRIM13 0xC
+#define PALMAS_GPADC_TRIM14 0xD
+#define PALMAS_GPADC_TRIM15 0xE
+#define PALMAS_GPADC_TRIM16 0xF
+
+#endif /* __LINUX_MFD_PALMAS_H */
diff --git a/include/linux/mfd/rc5t583.h b/include/linux/mfd/rc5t583.h
index a2c61609d21d..3661c59aa1e9 100644
--- a/include/linux/mfd/rc5t583.h
+++ b/include/linux/mfd/rc5t583.h
@@ -26,6 +26,7 @@
#include <linux/mutex.h>
#include <linux/types.h>
+#include <linux/regmap.h>
#define RC5T583_MAX_REGS 0xF8
@@ -249,6 +250,26 @@ enum {
RC5T583_EXT_PWRREQ2_CONTROL = 0x2,
};
+enum {
+ RC5T583_REGULATOR_DC0,
+ RC5T583_REGULATOR_DC1,
+ RC5T583_REGULATOR_DC2,
+ RC5T583_REGULATOR_DC3,
+ RC5T583_REGULATOR_LDO0,
+ RC5T583_REGULATOR_LDO1,
+ RC5T583_REGULATOR_LDO2,
+ RC5T583_REGULATOR_LDO3,
+ RC5T583_REGULATOR_LDO4,
+ RC5T583_REGULATOR_LDO5,
+ RC5T583_REGULATOR_LDO6,
+ RC5T583_REGULATOR_LDO7,
+ RC5T583_REGULATOR_LDO8,
+ RC5T583_REGULATOR_LDO9,
+
+ /* Should be last entry */
+ RC5T583_REGULATOR_MAX,
+};
+
struct rc5t583 {
struct device *dev;
struct regmap *regmap;
@@ -271,22 +292,63 @@ struct rc5t583 {
* rc5t583_platform_data: Platform data for ricoh rc5t583 pmu.
* The board specific data is provided through this structure.
* @irq_base: Irq base number on which this device registers their interrupts.
+ * @gpio_base: GPIO base from which gpio of this device will start.
* @enable_shutdown: Enable shutdown through the input pin "shutdown".
+ * @regulator_deepsleep_slot: The slot number on which device goes to sleep
+ * in device sleep mode.
+ * @regulator_ext_pwr_control: External power request regulator control. The
+ * regulator output enable/disable is controlled by the external
+ * power request input state.
+ * @reg_init_data: Regulator init data.
*/
struct rc5t583_platform_data {
int irq_base;
+ int gpio_base;
bool enable_shutdown;
+ int regulator_deepsleep_slot[RC5T583_REGULATOR_MAX];
+ unsigned long regulator_ext_pwr_control[RC5T583_REGULATOR_MAX];
+ struct regulator_init_data *reg_init_data[RC5T583_REGULATOR_MAX];
};
-int rc5t583_write(struct device *dev, u8 reg, uint8_t val);
-int rc5t583_read(struct device *dev, uint8_t reg, uint8_t *val);
-int rc5t583_set_bits(struct device *dev, unsigned int reg,
- unsigned int bit_mask);
-int rc5t583_clear_bits(struct device *dev, unsigned int reg,
- unsigned int bit_mask);
-int rc5t583_update(struct device *dev, unsigned int reg,
- unsigned int val, unsigned int mask);
+static inline 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);
+}
+
+static inline 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;
+}
+
+static inline 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);
+}
+
+static inline 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);
+}
+
+static inline 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);
+}
+
int rc5t583_ext_power_req_config(struct device *dev, int deepsleep_id,
int ext_pwr_req, int deepsleep_slot_nr);
int rc5t583_irq_init(struct rc5t583 *rc5t583, int irq, int irq_base);
diff --git a/include/linux/mfd/tps65910.h b/include/linux/mfd/tps65910.h
index f6021cc9d911..7e4395a2c21b 100644
--- a/include/linux/mfd/tps65910.h
+++ b/include/linux/mfd/tps65910.h
@@ -17,6 +17,9 @@
#ifndef __LINUX_MFD_TPS65910_H
#define __LINUX_MFD_TPS65910_H
+#include <linux/gpio.h>
+#include <linux/regmap.h>
+
/* TPS chip id list */
#define TPS65910 0
#define TPS65911 1
@@ -781,6 +784,18 @@
#define TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3 0x4
#define TPS65911_SLEEP_CONTROL_EXT_INPUT_SLEEP 0x8
+/*
+ * Sleep keepon data: Maintains the state in sleep mode
+ * @therm_keepon: Keep on the thermal monitoring in sleep state.
+ * @clkout32k_keepon: Keep on the 32KHz clock output in sleep state.
+ * @i2chs_keepon: Keep on high speed internal clock in sleep state.
+ */
+struct tps65910_sleep_keepon_data {
+ unsigned therm_keepon:1;
+ unsigned clkout32k_keepon:1;
+ unsigned i2chs_keepon:1;
+};
+
/**
* struct tps65910_board
* Board platform data may be used to initialize regulators.
@@ -792,6 +807,8 @@ struct tps65910_board {
int irq_base;
int vmbch_threshold;
int vmbch2_threshold;
+ bool en_dev_slp;
+ struct tps65910_sleep_keepon_data *slp_keepon;
unsigned long regulator_ext_sleep_control[TPS65910_NUM_REGS];
bool en_gpio_sleep[TPS6591X_MAX_NUM_GPIO];
struct regulator_init_data *tps65910_pmic_init_data[TPS65910_NUM_REGS];
@@ -807,17 +824,12 @@ struct tps65910 {
struct regmap *regmap;
struct mutex io_mutex;
unsigned int id;
- int (*read)(struct tps65910 *tps65910, u8 reg, int size, void *dest);
- int (*write)(struct tps65910 *tps65910, u8 reg, int size, void *src);
/* Client devices */
struct tps65910_pmic *pmic;
struct tps65910_rtc *rtc;
struct tps65910_power *power;
- /* GPIO Handling */
- struct gpio_chip gpio;
-
/* IRQ Handling */
struct mutex irq_lock;
int chip_irq;
@@ -831,9 +843,6 @@ struct tps65910_platform_data {
int irq_base;
};
-int tps65910_set_bits(struct tps65910 *tps65910, u8 reg, u8 mask);
-int tps65910_clear_bits(struct tps65910 *tps65910, u8 reg, u8 mask);
-void tps65910_gpio_init(struct tps65910 *tps65910, int gpio_base);
int tps65910_irq_init(struct tps65910 *tps65910, int irq,
struct tps65910_platform_data *pdata);
int tps65910_irq_exit(struct tps65910 *tps65910);
@@ -843,4 +852,28 @@ static inline int tps65910_chip_id(struct tps65910 *tps65910)
return tps65910->id;
}
+static inline int tps65910_reg_read(struct tps65910 *tps65910, u8 reg,
+ unsigned int *val)
+{
+ return regmap_read(tps65910->regmap, reg, val);
+}
+
+static inline int tps65910_reg_write(struct tps65910 *tps65910, u8 reg,
+ unsigned int val)
+{
+ return regmap_write(tps65910->regmap, reg, val);
+}
+
+static inline int tps65910_reg_set_bits(struct tps65910 *tps65910, u8 reg,
+ u8 mask)
+{
+ return regmap_update_bits(tps65910->regmap, reg, mask, mask);
+}
+
+static inline int tps65910_reg_clear_bits(struct tps65910 *tps65910, u8 reg,
+ u8 mask)
+{
+ return regmap_update_bits(tps65910->regmap, reg, mask, 0);
+}
+
#endif /* __LINUX_MFD_TPS65910_H */
diff --git a/include/linux/mfd/tps80031.h b/include/linux/mfd/tps80031.h
index 9623a873d311..b3b9480ce596 100644
--- a/include/linux/mfd/tps80031.h
+++ b/include/linux/mfd/tps80031.h
@@ -165,6 +165,7 @@ struct tps80031_subdev_info {
struct tps80031_rtc_platform_data {
int irq;
struct rtc_time time;
+ int msecure_gpio;
};
struct tps80031_clk32k_init_data {
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 9178aa48209a..8f17619931ab 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -22,6 +22,7 @@ struct mmc_cid {
unsigned char hwrev;
unsigned char fwrev;
unsigned char month;
+ unsigned short prod_rev;
};
struct mmc_csd {
@@ -83,6 +84,9 @@ struct mmc_ext_csd {
u8 out_of_int_time; /* out of int time */
bool bk_ops; /* BK ops support bit */
bool bk_ops_en; /* BK ops enable bit */
+ bool refresh; /* refresh of blocks supported */
+ __kernel_time_t last_tv_sec; /* last time a block was refreshed */
+ __kernel_time_t last_bkops_tv_sec; /* last time bkops was done */
};
struct sd_scr {
@@ -224,6 +228,10 @@ struct mmc_card {
unsigned int sd_bus_speed; /* Bus Speed Mode set for the card */
struct dentry *debugfs_root;
+
+ struct timer_list timer;
+ struct work_struct bkops;
+ struct work_struct refresh;
};
/*
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index c3e55fa63fb6..0c4472eff796 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -11,6 +11,10 @@
#include <linux/interrupt.h>
#include <linux/device.h>
+#define MMC_SLOW_WRITE_TIME 500000 /* time (us) */
+#define MMC_REFRESH_INTERVAL 60 /* time (s) */
+#define MMC_BKOPS_INTERVAL 20 /* time (s) */
+
struct request;
struct mmc_data;
struct mmc_request;
@@ -138,6 +142,7 @@ extern struct mmc_async_req *mmc_start_req(struct mmc_host *,
struct mmc_async_req *, int *);
extern int mmc_interrupt_hpi(struct mmc_card *);
extern int mmc_bkops_start(struct mmc_card *card, bool is_synchronous);
+extern void mmc_refresh(unsigned long data);
extern void mmc_wait_for_req(struct mmc_host *, struct mmc_request *);
extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int);
diff --git a/include/linux/nct1008.h b/include/linux/nct1008.h
index 0a517f1d6d89..69515a6f0bda 100644
--- a/include/linux/nct1008.h
+++ b/include/linux/nct1008.h
@@ -3,7 +3,7 @@
*
* NCT1008, temperature monitoring device from ON Semiconductors
*
- * Copyright (c) 2010, 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
@@ -24,6 +24,7 @@
#define _LINUX_NCT1008_H
#include <linux/types.h>
+#include <linux/workqueue.h>
#include <mach/edp.h>
@@ -31,6 +32,8 @@
struct nct1008_data;
+enum nct1008_chip { NCT1008, NCT72 };
+
struct nct1008_platform_data {
bool supported_hwrev;
bool ext_range;
@@ -56,6 +59,7 @@ struct nct1008_data {
u8 config;
s8 *limits;
u8 limits_sz;
+ enum nct1008_chip chip;
void (*alarm_fn)(bool raised);
struct regulator *nct_reg;
long current_lo_limit;
@@ -68,6 +72,8 @@ struct nct1008_data {
#ifdef CONFIG_SENSORS_NCT1008
int nct1008_thermal_get_temp(struct nct1008_data *data, long *temp);
+int nct1008_thermal_get_temps(struct nct1008_data *data, long *etemp,
+ long *itemp);
int nct1008_thermal_get_temp_low(struct nct1008_data *data, long *temp);
int nct1008_thermal_set_limits(struct nct1008_data *data,
long lo_limit_milli,
@@ -81,6 +87,9 @@ int nct1008_thermal_set_shutdown_temp(struct nct1008_data *data,
static inline int nct1008_thermal_get_temp(struct nct1008_data *data,
long *temp)
{ return -EINVAL; }
+static inline int nct1008_thermal_get_temps(struct nct1008_data *data,
+ long *etemp, long *itemp)
+{ return -EINVAL; }
static inline int nct1008_thermal_get_temp_low(struct nct1008_data *data,
long *temp)
{ return -EINVAL; }
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 8ad70dcac3f9..bec6bcacc899 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -967,6 +967,8 @@ enum nl80211_commands {
* @NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX: Bitmap of antennas which are available
* for configuration as RX antennas via the above parameters.
*
+ * @NL80211_ATTR_SCAN_FLAGS: scan request control flags (u32)
+ *
* @NL80211_ATTR_MCAST_RATE: Multicast tx rate (in 100 kbps) for IBSS
*
* @NL80211_ATTR_OFFCHANNEL_TX_OK: For management frame TX, the frame may be
@@ -1206,6 +1208,8 @@ enum nl80211_attrs {
NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX,
NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX,
+ NL80211_ATTR_SCAN_FLAGS,
+
NL80211_ATTR_SUPPORT_MESH_AUTH,
NL80211_ATTR_STA_PLINK_STATE,
@@ -2207,6 +2211,18 @@ enum nl80211_tx_power_setting {
};
/**
+ * enum nl80211_scan_flags - scan request control flags
+ *
+ * Scan request control flags are used to control the handling
+ * of NL80211_CMD_TRIGGER_SCAN, requests.
+ *
+ * @NL80211_SCAN_FLAG_TX_ABORT: abort scan if tx collides
+ */
+enum nl80211_scan_flags {
+ NL80211_SCAN_FLAG_TX_ABORT = 1<<0,
+};
+
+/**
* enum nl80211_wowlan_packet_pattern_attr - WoWLAN packet pattern attribute
* @__NL80211_WOWLAN_PKTPAT_INVALID: invalid number for nested attribute
* @NL80211_WOWLAN_PKTPAT_PATTERN: the pattern, values where the mask has
diff --git a/include/linux/nvhost.h b/include/linux/nvhost.h
index faa183d40d6d..cde63fa6abb7 100644
--- a/include/linux/nvhost.h
+++ b/include/linux/nvhost.h
@@ -3,7 +3,7 @@
*
* Tegra graphics host driver
*
- * Copyright (c) 2009-2012, NVIDIA Corporation.
+ * 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
@@ -28,10 +28,44 @@
struct nvhost_master;
-#define NVHOST_MODULE_MAX_CLOCKS 3
-#define NVHOST_MODULE_MAX_POWERGATE_IDS 2
-#define NVHOST_MODULE_NO_POWERGATE_IDS .powergate_ids = {-1, -1}
-#define NVHOST_DEFAULT_CLOCKGATE_DELAY .clockgate_delay = 25
+struct nvhost_device_power_attr;
+
+#define NVHOST_MODULE_MAX_CLOCKS 3
+#define NVHOST_MODULE_MAX_POWERGATE_IDS 2
+#define NVHOST_MODULE_NO_POWERGATE_IDS .powergate_ids = {-1, -1}
+#define NVHOST_DEFAULT_CLOCKGATE_DELAY .clockgate_delay = 25
+#define NVHOST_NAME_SIZE 24
+#define NVSYNCPT_INVALID (-1)
+
+/* FIXME:
+ * Sync point ids are now split into 2 files.
+ * 1 if this one and other is in
+ * drivers/video/tegra/host/host1x/host1x_syncpt.h
+ * So if someone decides to add new sync point in future
+ * please check both the header files
+ */
+#define NVSYNCPT_DISP0_A (8)
+#define NVSYNCPT_DISP1_A (9)
+#define NVSYNCPT_AVP_0 (10)
+#define NVSYNCPT_DISP0_B (20)
+#define NVSYNCPT_DISP1_B (21)
+#define NVSYNCPT_DISP0_C (24)
+#define NVSYNCPT_DISP1_C (25)
+#define NVSYNCPT_VBLANK0 (26)
+#define NVSYNCPT_VBLANK1 (27)
+#define NVSYNCPT_DSI (31)
+
+enum nvhost_power_sysfs_attributes {
+ NVHOST_POWER_SYSFS_ATTRIB_CLOCKGATE_DELAY = 0,
+ NVHOST_POWER_SYSFS_ATTRIB_POWERGATE_DELAY,
+ NVHOST_POWER_SYSFS_ATTRIB_REFCOUNT,
+ NVHOST_POWER_SYSFS_ATTRIB_MAX
+};
+
+struct nvhost_device_id {
+ char name[NVHOST_NAME_SIZE];
+ unsigned long version;
+};
struct nvhost_clock {
char *name;
@@ -46,7 +80,8 @@ enum nvhost_device_powerstate_t {
};
struct nvhost_device {
- const char *name; /* Device name */
+ const char *name; /* device name */
+ int version; /* ip version number of device */
struct device dev; /* Linux device struct */
int id; /* Separates clients of same hw */
int index; /* Hardware channel number */
@@ -65,6 +100,7 @@ struct nvhost_device {
bool keepalive; /* Do not power gate when opened */
bool waitbasesync; /* Force sync of wait bases */
bool powerup_reset; /* Do a reset after power un-gating */
+ bool serialize; /* Serialize submits in the channel */
int powergate_ids[NVHOST_MODULE_MAX_POWERGATE_IDS];
bool can_powergate; /* True if module can be power gated */
@@ -82,26 +118,18 @@ struct nvhost_device {
struct list_head client_list; /* List of clients and rate requests */
struct nvhost_channel *channel; /* Channel assigned for the module */
+ struct kobject *power_kobj; /* kobject to hold power sysfs entries */
+ struct nvhost_device_power_attr *power_attrib; /* sysfs attributes */
+};
- /* Allocates a context handler for the device */
- struct nvhost_hwctx_handler *(*alloc_hwctx_handler)(u32 syncpt,
- u32 waitbase, struct nvhost_channel *ch);
- /* Preparing for power off. Used for context save. */
- int (*prepare_poweroff)(struct nvhost_device *dev);
- /* Finalize power on. Can be used for context restore. */
- void (*finalize_poweron)(struct nvhost_device *dev);
- /* Device is busy. */
- void (*busy)(struct nvhost_device *);
- /* Device is idle. */
- void (*idle)(struct nvhost_device *);
- /* Device is going to be suspended */
- void (*suspend)(struct nvhost_device *);
- /* Device is initialized */
- void (*init)(struct nvhost_device *dev);
- /* Device is de-initialized. */
- void (*deinit)(struct nvhost_device *dev);
+struct nvhost_device_power_attr {
+ struct nvhost_device *ndev;
+ struct kobj_attribute power_attr[NVHOST_POWER_SYSFS_ATTRIB_MAX];
};
+/* Register devices to nvhost bus */
+extern int nvhost_add_devices(struct nvhost_device **, int num);
+
/* Register device to nvhost bus */
extern int nvhost_device_register(struct nvhost_device *);
@@ -111,12 +139,39 @@ extern void nvhost_device_unregister(struct nvhost_device *);
extern struct bus_type nvhost_bus_type;
struct nvhost_driver {
- int (*probe)(struct nvhost_device *);
+ int (*probe)(struct nvhost_device *, struct nvhost_device_id *);
int (*remove)(struct nvhost_device *);
void (*shutdown)(struct nvhost_device *);
int (*suspend)(struct nvhost_device *, pm_message_t state);
int (*resume)(struct nvhost_device *);
struct device_driver driver;
+
+ struct nvhost_device_id *id_table;
+
+ /* Finalize power on. Can be used for context restore. */
+ void (*finalize_poweron)(struct nvhost_device *dev);
+
+ /* Device is busy. */
+ void (*busy)(struct nvhost_device *);
+
+ /* Device is idle. */
+ void (*idle)(struct nvhost_device *);
+
+ /* Device is going to be suspended */
+ void (*suspend_ndev)(struct nvhost_device *);
+
+ /* Device is initialized */
+ void (*init)(struct nvhost_device *dev);
+
+ /* Device is de-initialized. */
+ void (*deinit)(struct nvhost_device *dev);
+
+ /* Preparing for power off. Used for context save. */
+ int (*prepare_poweroff)(struct nvhost_device *dev);
+
+ /* Allocates a context handler for the device */
+ struct nvhost_hwctx_handler *(*alloc_hwctx_handler)(u32 syncpt,
+ u32 waitbase, struct nvhost_channel *ch);
};
extern int nvhost_driver_register(struct nvhost_driver *);
@@ -128,19 +183,30 @@ extern struct resource *nvhost_get_resource_byname(struct nvhost_device *,
unsigned int, const char *);
extern int nvhost_get_irq_byname(struct nvhost_device *, const char *);
-#define to_nvhost_device(x) container_of((x), struct nvhost_device, dev)
+#define to_nvhost_device(x) container_of((x), struct nvhost_device, dev)
#define to_nvhost_driver(drv) (container_of((drv), struct nvhost_driver, \
driver))
#define nvhost_get_drvdata(_dev) dev_get_drvdata(&(_dev)->dev)
#define nvhost_set_drvdata(_dev, data) dev_set_drvdata(&(_dev)->dev, (data))
-static inline struct nvhost_master *nvhost_get_host(struct nvhost_device *_dev)
+
+int nvhost_bus_add_host(struct nvhost_master *host);
+
+static inline struct nvhost_device *nvhost_get_parent(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)));
+ return _dev->dev.parent ? to_nvhost_device(_dev->dev.parent) : NULL;
}
-int nvhost_bus_add_host(struct nvhost_master *host);
+/* public host1x power management APIs */
+bool nvhost_module_powered_ext(struct nvhost_device *dev);
+void nvhost_module_busy_ext(struct nvhost_device *dev);
+void nvhost_module_idle_ext(struct nvhost_device *dev);
+
+/* public host1x sync-point management APIs */
+u32 nvhost_syncpt_incr_max_ext(struct nvhost_device *dev, u32 id, u32 incrs);
+void nvhost_syncpt_cpu_incr_ext(struct nvhost_device *dev, u32 id);
+u32 nvhost_syncpt_read_ext(struct nvhost_device *dev, u32 id);
+int nvhost_syncpt_wait_timeout_ext(struct nvhost_device *dev, u32 id, u32 thresh,
+ u32 timeout, u32 *value);
#endif
diff --git a/arch/arm/mach-tegra/include/mach/nvmap.h b/include/linux/nvmap.h
index 88f913fc29dd..553a7bd01a6d 100644
--- a/arch/arm/mach-tegra/include/mach/nvmap.h
+++ b/include/linux/nvmap.h
@@ -1,9 +1,9 @@
/*
- * arch/arm/mach-tegra/include/mach/nvmap.h
+ * include/linux/nvmap.h
*
* structure declarations for nvmem and nvmap user-space ioctls
*
- * Copyright (c) 2009-2011, NVIDIA Corporation.
+ * Copyright (c) 2009-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
@@ -28,8 +28,8 @@
#define __user
#endif
-#ifndef __NVMAP_H
-#define __NVMAP_H
+#ifndef _LINUX_NVMAP_H
+#define _LINUX_NVMAP_H
#define NVMAP_HEAP_SYSMEM (1ul<<31)
#define NVMAP_HEAP_IOVMM (1ul<<30)
@@ -50,20 +50,31 @@
#define NVMAP_HANDLE_SECURE (0x1ul << 2)
-
#if defined(__KERNEL__)
#if defined(CONFIG_TEGRA_NVMAP)
struct nvmap_handle;
struct nvmap_client;
struct nvmap_device;
+
#define nvmap_ref_to_handle(_ref) (*(struct nvmap_handle **)(_ref))
/* Convert User space handle to Kernel. */
#define nvmap_convert_handle_u2k(h) (h)
+
+/* handle_ref objects are client-local references to an nvmap_handle;
+ * they are distinct objects so that handles can be unpinned and
+ * unreferenced the correct number of times when a client abnormally
+ * terminates */
+struct nvmap_handle_ref {
+ struct nvmap_handle *handle;
+ struct rb_node node;
+ atomic_t dupes; /* number of times to free on file close */
+ atomic_t pin; /* number of times to unpin on free */
+};
+
#elif defined(CONFIG_ION_TEGRA)
/* For Ion Mem Manager support through nvmap_* API's. */
#include "../../../../../drivers/gpu/ion/ion_priv.h"
-
#define nvmap_client ion_client
#define nvmap_device ion_device
#define nvmap_handle ion_handle
@@ -76,31 +87,10 @@ struct nvmap_device;
BUG(); \
} \
(*((u32 *)h)); })
-#endif
-
-#define nvmap_id_to_handle(_id) ((struct nvmap_handle *)(_id))
+#endif /* CONFIG_ION_TEGRA */
-struct nvmap_pinarray_elem {
- __u32 patch_mem;
- __u32 patch_offset;
- __u32 pin_mem;
- __u32 pin_offset;
- __u32 reloc_shift;
-};
-
-#if defined(CONFIG_TEGRA_NVMAP)
-/* handle_ref objects are client-local references to an nvmap_handle;
- * they are distinct objects so that handles can be unpinned and
- * unreferenced the correct number of times when a client abnormally
- * terminates */
-struct nvmap_handle_ref {
- struct nvmap_handle *handle;
- struct rb_node node;
- atomic_t dupes; /* number of times to free on file close */
- atomic_t pin; /* number of times to unpin on free */
-};
-#endif
+#define nvmap_id_to_handle(_id) ((struct nvmap_handle *)(_id))
struct nvmap_client *nvmap_create_client(struct nvmap_device *dev,
const char *name);
@@ -127,16 +117,11 @@ phys_addr_t nvmap_handle_address(struct nvmap_client *c, unsigned long id);
void nvmap_unpin(struct nvmap_client *client, struct nvmap_handle_ref *r);
-int nvmap_pin_array(struct nvmap_client *client, struct nvmap_handle *gather,
- const struct nvmap_pinarray_elem *arr, int nr,
- struct nvmap_handle **unique);
-
void nvmap_unpin_handles(struct nvmap_client *client,
struct nvmap_handle **h, int nr);
-int nvmap_patch_word(struct nvmap_client *client,
- struct nvmap_handle *patch,
- u32 patch_offset, u32 patch_value);
+struct nvmap_handle_ref *nvmap_duplicate_handle_id(struct nvmap_client *client,
+ unsigned long id);
struct nvmap_platform_carveout {
const char *name;
@@ -153,6 +138,6 @@ struct nvmap_platform_data {
extern struct nvmap_device *nvmap_dev;
-#endif
+#endif /* __KERNEL__ */
-#endif
+#endif /* _LINUX_NVMAP_H */
diff --git a/include/linux/of.h b/include/linux/of.h
index 9180dc5cb00b..c4b5b52a7515 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -235,6 +235,7 @@ extern void of_attach_node(struct device_node *);
extern void of_detach_node(struct device_node *);
#endif
+#define of_match_ptr(_ptr) (_ptr)
#else /* CONFIG_OF */
static inline bool of_have_populated_dt(void)
@@ -263,6 +264,7 @@ static inline const void *of_get_property(const struct device_node *node,
return NULL;
}
+#define of_match_ptr(_ptr) NULL
#endif /* CONFIG_OF */
static inline int of_property_read_u32(const struct device_node *np,
diff --git a/include/linux/platform_data/tegra_usb.h b/include/linux/platform_data/tegra_usb.h
index e6377c379b48..6499eeaff6a3 100644
--- a/include/linux/platform_data/tegra_usb.h
+++ b/include/linux/platform_data/tegra_usb.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2010 Google, Inc.
- * 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
@@ -16,33 +16,136 @@
#ifndef _TEGRA_USB_H_
#define _TEGRA_USB_H_
-enum tegra_usb_operating_modes {
- TEGRA_USB_DEVICE,
- TEGRA_USB_HOST,
- TEGRA_USB_OTG,
+/**
+ * defines operation mode of the USB controller
+ */
+enum tegra_usb_operation_mode {
+ TEGRA_USB_OPMODE_DEVICE,
+ TEGRA_USB_OPMODE_HOST,
};
-enum tegra_usb_phy_type {
- TEGRA_USB_PHY_TYPE_UTMIP = 0,
- TEGRA_USB_PHY_TYPE_LINK_ULPI = 1,
- TEGRA_USB_PHY_TYPE_NULL_ULPI = 2,
- TEGRA_USB_PHY_TYPE_HSIC = 3,
- TEGRA_USB_PHY_TYPE_ICUSB = 4,
+/**
+ * defines the various phy interface mode supported by controller
+ */
+enum tegra_usb_phy_interface {
+ TEGRA_USB_PHY_INTF_UTMI = 0,
+ TEGRA_USB_PHY_INTF_ULPI_LINK = 1,
+ TEGRA_USB_PHY_INTF_ULPI_NULL = 2,
+ TEGRA_USB_PHY_INTF_HSIC = 3,
+ TEGRA_USB_PHY_INTF_ICUSB = 4,
};
-struct tegra_ehci_platform_data {
- enum tegra_usb_operating_modes operating_mode;
- /* power down the phy on bus suspend */
- int power_down_on_bus_suspend;
- int hotplug;
- int default_enable;
- void *phy_config;
- enum tegra_usb_phy_type phy_type;
+/**
+ * configuration structure for setting up utmi phy
+ */
+struct tegra_utmi_config {
+ u8 hssync_start_delay;
+ u8 elastic_limit;
+ u8 idle_wait_delay;
+ u8 term_range_adj;
+ u8 xcvr_setup;
+ u8 xcvr_lsfslew;
+ u8 xcvr_lsrslew;
+ signed char xcvr_setup_offset;
+ u8 xcvr_use_lsb;
+ u8 xcvr_use_fuses;
};
-struct tegra_otg_platform_data {
+/**
+ * configuration structure for setting up ulpi phy
+ */
+struct tegra_ulpi_config {
+ u8 shadow_clk_delay;
+ u8 clock_out_delay;
+ u8 data_trimmer;
+ u8 stpdirnxt_trimmer;
+ u8 dir_trimmer;
+ const char *clk;
+ int phy_restore_gpio;
+};
+
+/**
+ * configuration structure for setting up hsic phy
+ */
+struct tegra_hsic_config {
+ u8 sync_start_delay;
+ u8 idle_wait_delay;
+ u8 term_range_adj;
+ u8 elastic_underrun_limit;
+ u8 elastic_overrun_limit;
+};
+
+/**
+ * Platform specific operations that will be controlled
+ * during the phy operations.
+ */
+struct tegra_usb_phy_platform_ops {
+ void (*open)(void);
+ void (*init)(void);
+ void (*pre_suspend)(void);
+ void (*post_suspend)(void);
+ void (*pre_resume)(void);
+ void (*post_resume)(void);
+ void (*pre_phy_off)(void);
+ void (*post_phy_off)(void);
+ void (*pre_phy_on)(void);
+ void (*post_phy_on)(void);
+ void (*port_power)(void);
+ void (*close)(void);
+};
+
+/**
+ * defines structure for platform dependent device parameters
+ */
+struct tegra_usb_dev_mode_data {
+ int vbus_pmu_irq;
+ int vbus_gpio;
+ bool charging_supported;
+ bool remote_wakeup_supported;
+};
+
+/**
+ * defines structure for platform dependent host parameters
+ */
+struct tegra_usb_host_mode_data {
+ int vbus_gpio;
+ int vbus_gpio_inverted;
+ const char *vbus_reg;
+ bool hot_plug;
+ bool remote_wakeup_supported;
+ bool power_off_on_suspend;
+};
+
+/**
+ * defines structure for usb platform data
+ */
+struct tegra_usb_platform_data {
+ bool port_otg;
+ bool has_hostpc;
+ bool builtin_host_disabled;
+ enum tegra_usb_phy_interface phy_intf;
+ enum tegra_usb_operation_mode op_mode;
+
+ union {
+ struct tegra_usb_dev_mode_data dev;
+ struct tegra_usb_host_mode_data host;
+ } u_data;
+
+ union {
+ struct tegra_utmi_config utmi;
+ struct tegra_ulpi_config ulpi;
+ struct tegra_hsic_config hsic;
+ } u_cfg;
+
+ struct tegra_usb_phy_platform_ops *ops;
+};
+
+/**
+ * defines structure for platform dependent OTG parameters
+ */
+struct tegra_usb_otg_data {
struct platform_device *ehci_device;
- struct tegra_ehci_platform_data *ehci_pdata;
+ struct tegra_usb_platform_data *ehci_pdata;
};
#endif /* _TEGRA_USB_H_ */
diff --git a/include/linux/pm_qos_params.h b/include/linux/pm_qos_params.h
index 5a536cbb25b8..be63f01630a3 100644
--- a/include/linux/pm_qos_params.h
+++ b/include/linux/pm_qos_params.h
@@ -28,7 +28,7 @@ enum {
#define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC)
#define PM_QOS_NETWORK_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC)
#define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE 0
-#define PM_QOS_MIN_ONLINE_CPUS_DEFAULT_VALUE 1
+#define PM_QOS_MIN_ONLINE_CPUS_DEFAULT_VALUE 0
#define PM_QOS_MAX_ONLINE_CPUS_DEFAULT_VALUE LONG_MAX
#define PM_QOS_CPU_FREQ_MIN_DEFAULT_VALUE 0
#define PM_QOS_CPU_FREQ_MAX_DEFAULT_VALUE LONG_MAX
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index 6986d16aeca8..3a97248c5125 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -212,6 +212,7 @@ struct regmap_irq {
* @status_base: Base status register address.
* @mask_base: Base mask register address.
* @ack_base: Base ack address. If zero then the chip is clear on read.
+ * @irq_reg_stride: Stride to use for chips where registers are not contiguous.
*
* @num_regs: Number of registers in each control bank.
* @irqs: Descriptors for individual IRQs. Interrupt numbers are
@@ -224,6 +225,7 @@ struct regmap_irq_chip {
unsigned int status_base;
unsigned int mask_base;
unsigned int ack_base;
+ unsigned int irq_reg_stride;
int num_regs;
diff --git a/include/linux/regulator/max8973-regulator.h b/include/linux/regulator/max8973-regulator.h
new file mode 100644
index 000000000000..4b86e88b028e
--- /dev/null
+++ b/include/linux/regulator/max8973-regulator.h
@@ -0,0 +1,77 @@
+/*
+ * max8973-regulator.h -- MAXIM 8973 regulator
+ *
+ * Interface for 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; 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 __LINUX_REGULATOR_MAX8973_H
+#define __LINUX_REGULATOR_MAX8973_H
+
+/*
+ * Control flags for configuration of the device.
+ * Client need to pass this information with ORed
+ */
+#define MAX8973_CONTROL_REMOTE_SENSE_ENABLE 0x00000001
+#define MAX8973_CONTROL_FALLING_SLEW_RATE_ENABLE 0x00000002
+#define MAX8973_CONTROL_OUTPUT_ACTIVE_DISCH_ENABLE 0x00000004
+#define MAX8973_CONTROL_BIAS_ENABLE 0x00000008
+#define MAX8973_CONTROL_PULL_DOWN_ENABLE 0x00000010
+#define MAX8973_CONTROL_FREQ_SHIFT_9PER_ENABLE 0x00000020
+
+#define MAX8973_CONTROL_SLEW_RATE_12_5mV_PER_US 0x00000000
+#define MAX8973_CONTROL_SLEW_RATE_25mV_PER_US 0x00000100
+#define MAX8973_CONTROL_SLEW_RATE_50mV_PER_US 0x00000200
+#define MAX8973_CONTROL_SLEW_RATE_200MV_PER_US 0x00000300
+
+#define MAX8973_CONTROL_CLKADV_TRIP_DISABLED 0x00000000
+#define MAX8973_CONTROL_CLKADV_TRIP_75mV_PER_US 0x00010000
+#define MAX8973_CONTROL_CLKADV_TRIP_150mV_PER_US 0x00020000
+#define MAX8973_CONTROL_CLKADV_TRIP_75mV_PER_US_HIST_DIS 0x00030000
+
+#define MAX8973_CONTROL_INDUCTOR_VALUE_NOMINAL 0x00000000
+#define MAX8973_CONTROL_INDUCTOR_VALUE_MINUS_30_PER 0x00100000
+#define MAX8973_CONTROL_INDUCTOR_VALUE_PLUS_30_PER 0x00200000
+#define MAX8973_CONTROL_INDUCTOR_VALUE_PLUS_60_PER 0x00300000
+
+/*
+ * struct max8973_regulator_platform_data - max8973 regulator platform data.
+ *
+ * @reg_init_data: The regulator init data.
+ * @control_flags: Control flags which are ORed value of above flags to
+ * configure device.
+ * @enable_ext_control: Enable the voltage enable/disable through external
+ * control signal from EN input pin. If it is false then
+ * voltage output will be enabled/disabled through EN bit of
+ * device register.
+ * @dvs_gpio: GPIO for dvs. It should be -1 if this is tied with fixed logic.
+ * @dvs_def_state: Default state of dvs. 1 if it is high else 0.
+ */
+struct max8973_regulator_platform_data {
+ struct regulator_init_data *reg_init_data;
+ unsigned long control_flags;
+ bool enable_ext_control;
+ int dvs_gpio;
+ unsigned dvs_def_state:1;
+};
+
+#endif /* __LINUX_REGULATOR_MAX8973_H */
diff --git a/include/linux/regulator/tps62360.h b/include/linux/regulator/tps62360.h
index 6a5c1b2c751e..6475cd029c42 100644
--- a/include/linux/regulator/tps62360.h
+++ b/include/linux/regulator/tps62360.h
@@ -32,7 +32,6 @@
* struct tps62360_regulator_platform_data - tps62360 regulator platform data.
*
* @reg_init_data: The regulator init data.
- * @en_force_pwm: Enable force pwm or not.
* @en_discharge: Enable discharge the output capacitor via internal
* register.
* @en_internal_pulldn: internal pull down enable or not.
@@ -45,7 +44,6 @@
*/
struct tps62360_regulator_platform_data {
struct regulator_init_data reg_init_data;
- bool en_force_pwm;
bool en_discharge;
bool en_internal_pulldn;
int vsel0_gpio;
diff --git a/include/linux/regulator/tps6238x0-regulator.h b/include/linux/regulator/tps6238x0-regulator.h
new file mode 100644
index 000000000000..d7c4edc5b101
--- /dev/null
+++ b/include/linux/regulator/tps6238x0-regulator.h
@@ -0,0 +1,46 @@
+/*
+ * tps6238x0-regulator.h -- TI TPS623850/TPS623860/TPS623870
+ *
+ * Interface for regulator driver for TI TPS623850/TPS623860/TPS623870
+ * Processor core supply
+ *
+ * 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; 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 __LINUX_REGULATOR_TPS6238X0_H
+#define __LINUX_REGULATOR_TPS6238X0_H
+
+/*
+ * struct tps6238x0_regulator_platform_data - tps62360 regulator platform data.
+ *
+ * @init_data: The regulator init data.
+ * @en_internal_pulldn: internal pull down enable or not.
+ * @vsel_gpio: Gpio number for vsel. It should be -1 if this is tied with
+ * fixed logic.
+ * @vsel_def_state: Default state of vsel. 1 if it is high else 0.
+ */
+struct tps6238x0_regulator_platform_data {
+ struct regulator_init_data *init_data;
+ bool en_internal_pulldn;
+ int vsel_gpio;
+ int vsel_def_state;
+};
+
+#endif /* __LINUX_REGULATOR_TPS6238X0_H */
diff --git a/include/linux/regulator/tps80031-regulator.h b/include/linux/regulator/tps80031-regulator.h
index 1670d147fc3e..4dfdf7950918 100644
--- a/include/linux/regulator/tps80031-regulator.h
+++ b/include/linux/regulator/tps80031-regulator.h
@@ -74,6 +74,9 @@ enum {
* @flags: Configuration flag to configure the rails. It should be ORed of
* above enums.
* @delay_us: Delay in microsecond after setting the desired voltage.
+ * @tolerance_uv: Tolerance micorvolts in minimum side. The voltage min
+ * will be adjusted to this tolerance like
+ * actual_vmin = vmin - tolerance_uv
*/
struct tps80031_regulator_platform_data {
@@ -84,6 +87,7 @@ struct tps80031_regulator_platform_data {
unsigned int ext_ctrl_flag;
unsigned int flags;
int delay_us;
+ unsigned int tolerance_uv;
};
#endif /* __REGULATOR_TPS80031_H */
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 5bb4dd2e4c59..c9e03a9aa956 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -139,6 +139,7 @@ extern int nr_processes(void);
extern unsigned long nr_running(void);
extern unsigned long nr_uninterruptible(void);
extern unsigned long nr_iowait(void);
+extern unsigned long avg_nr_running(void);
extern unsigned long nr_iowait_cpu(int cpu);
extern unsigned long this_cpu_load(void);
diff --git a/include/linux/smb349-charger.h b/include/linux/smb349-charger.h
index 089f3976dbbe..228069e347a7 100644
--- a/include/linux/smb349-charger.h
+++ b/include/linux/smb349-charger.h
@@ -3,7 +3,7 @@
*
* Battery charger driver interface for Summit SMB349
*
- * 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
@@ -35,6 +35,9 @@ struct smb349_charger_platform_data {
int charging_term_current_mA;
int num_consumer_supplies;
struct regulator_consumer_supply *consumer_supplies;
+ int otg_regulator_id;
+ int num_otg_consumer_supplies;
+ struct regulator_consumer_supply *otg_consumer_supplies;
};
enum charging_states {
@@ -61,20 +64,21 @@ struct smb349_charger {
enum charger_type chrg_type;
charging_callback_t charger_cb;
+ int is_otg_enabled;
struct regulator_dev *rdev;
struct regulator_desc reg_desc;
struct regulator_init_data reg_init_data;
+ struct regulator_dev *otg_rdev;
+ struct regulator_desc otg_reg_desc;
+ struct regulator_init_data otg_reg_init_data;
};
int smb349_battery_online(void);
-typedef void (*callback_t)(enum usb_otg_state to,
- enum usb_otg_state from, void *args);
/*
* Register callback function for the client.
* Used by fuel-gauge driver to get battery charging properties.
*/
extern int register_callback(charging_callback_t cb, void *args);
-extern int register_otg_callback(callback_t cb, void *args);
extern int update_charger_status(void);
#endif /*__LINUX_SMB349_CHARGER_H */
diff --git a/include/linux/tegra_audio.h b/include/linux/tegra_audio.h
index 3975913a5206..650b0ac7265d 100644
--- a/include/linux/tegra_audio.h
+++ b/include/linux/tegra_audio.h
@@ -76,9 +76,9 @@ struct dam_srate {
#define I2S_MODE_I2S _IOW(TEGRA_AUDIO_MAGIC, 18, unsigned int *)
#ifdef CONFIG_SND_SOC_TEGRA
-extern bool tegra_is_voice_call_active();
+extern bool tegra_is_voice_call_active(void);
#else
-static inline bool tegra_is_voice_call_active()
+static inline bool tegra_is_voice_call_active(void)
{
return false;
}
diff --git a/include/linux/tegra_pwm_bl.h b/include/linux/tegra_pwm_bl.h
index 71a81f2eda88..3ed5e8a3c0a9 100644
--- a/include/linux/tegra_pwm_bl.h
+++ b/include/linux/tegra_pwm_bl.h
@@ -17,7 +17,6 @@
struct platform_tegra_pwm_backlight_data {
int which_dc;
int which_pwm;
- void (*switch_to_sfio)(int);
int gpio_conf_to_sfio;
unsigned int dft_brightness;
unsigned int max_brightness;
diff --git a/include/linux/therm_est.h b/include/linux/therm_est.h
new file mode 100644
index 000000000000..035b08fa9813
--- /dev/null
+++ b/include/linux/therm_est.h
@@ -0,0 +1,77 @@
+/*
+ * include/linux/therm_est.h
+ *
+ * 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.
+ *
+ */
+
+#ifndef _LINUX_THERM_EST_H
+#define _LINUX_THERM_EST_H
+
+#include <linux/workqueue.h>
+
+#define HIST_LEN (20)
+
+struct therm_est_subdevice {
+ void *dev_data;
+ int (*get_temp)(void *, long *);
+ long coeffs[HIST_LEN];
+ long hist[HIST_LEN];
+};
+
+struct therm_estimator {
+ long therm_est_lo_limit;
+ long therm_est_hi_limit;
+ void (*callback)(void *);
+ void *callback_data;
+ long cur_temp;
+ long polling_period;
+ struct workqueue_struct *workqueue;
+ struct delayed_work therm_est_work;
+ long toffset;
+ int ntemp;
+ int ndevs;
+ struct therm_est_subdevice **devs;
+};
+
+#ifdef CONFIG_THERM_EST
+struct therm_estimator *therm_est_register(
+ struct therm_est_subdevice **devs,
+ int ndevs,
+ long toffset,
+ long pperiod);
+int therm_est_get_temp(struct therm_estimator *est, long *temp);
+int therm_est_set_limits(struct therm_estimator *est,
+ long lo_limit,
+ long hi_limit);
+int therm_est_set_alert(struct therm_estimator *est,
+ void (*cb)(void *),
+ void *cb_data);
+#else
+static inline struct therm_estimator *therm_est_register(
+ struct therm_est_subdevice **devs,
+ int ndevs,
+ long toffset,
+ long pperiod)
+{ return NULL; }
+static inline int therm_est_get_temp(struct therm_estimator *est, long *temp)
+{ return -EINVAL; }
+static inline int therm_est_set_limits(struct therm_estimator *est,
+ long lo_limit,
+ long hi_limit)
+{ return -EINVAL; }
+static inline int therm_est_set_alert(struct therm_estimator *est,
+ void (*cb)(void *),
+ void *cb_data)
+{ return -EINVAL; }
+#endif
+#endif /* _LINUX_THERM_EST_H */
diff --git a/include/media/ad5816.h b/include/media/ad5816.h
new file mode 100644
index 000000000000..c51417ca472b
--- /dev/null
+++ b/include/media/ad5816.h
@@ -0,0 +1,79 @@
+/*
+ * 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
+ */
+
+#ifndef __AD5816_H__
+#define __AD5816_H__
+
+#include <media/nvc_focus.h>
+#include <media/nvc.h>
+
+typedef enum {
+ AD5816_VREG_VDD = 0,
+ AD5816_VREG_VDD_AF,
+ AD5816_VREG_VDD_I2C
+} ad5816_vreg;
+
+typedef enum {
+ AD5816_GPIO_RESET = 0,
+ AD5816_GPIO_I2CMUX,
+ AD5816_GPIO_GP1,
+ AD5816_GPIO_GP2,
+ AD5816_GPIO_GP3
+} ad5816_gpio_types;
+
+
+struct ad5816_platform_data {
+ int cfg;
+ int num;
+ int sync;
+ const char *dev_name;
+ struct nvc_focus_nvc (*nvc);
+ struct nvc_focus_cap (*cap);
+ struct ad5816_pdata_info (*info);
+ int gpio_count;
+ struct nvc_gpio_pdata *gpio;
+};
+
+struct ad5816_pdata_info {
+ float focal_length;
+ float fnumber;
+ __u32 settle_time;
+ __s16 pos_low;
+ __s16 pos_high;
+ __s16 limit_low;
+ __s16 limit_high;
+ int move_timeoutms;
+ __u32 focus_hyper_ratio;
+ __u32 focus_hyper_div;
+};
+
+// Register Definitions
+
+#define IC_INFO 0x00
+#define IC_VERSION 0x01
+#define CONTROL 0x02
+#define VCM_CODE_MSB 0x03
+#define VCM_CODE_LSB 0x04
+#define STATUS 0x05
+#define MODE 0x06
+#define VCM_FREQ 0x07
+#define VCM_THRESHOLD 0x08
+
+
+#endif
+/* __AD5816_H__ */
diff --git a/include/media/ar0832_main.h b/include/media/ar0832_main.h
index f5e3713b46fb..fe46c228a9f1 100644
--- a/include/media/ar0832_main.h
+++ b/include/media/ar0832_main.h
@@ -12,6 +12,7 @@
#define __AR0832_MAIN_H__
#include <linux/ioctl.h> /* For IOCTL macros */
+#include <media/nvc_focus.h>
#define AR0832_IOCTL_SET_MODE _IOW('o', 0x01, struct ar0832_mode)
#define AR0832_IOCTL_SET_FRAME_LENGTH _IOW('o', 0x02, __u32)
@@ -23,10 +24,11 @@
#define AR0832_IOCTL_SET_POWER_ON _IOW('o', 0x08, struct ar0832_mode)
#define AR0832_IOCTL_SET_SENSOR_REGION _IOW('o', 0x09, struct ar0832_stereo_region)
-#define AR0832_FOCUSER_IOCTL_GET_CONFIG _IOR('o', 0x10, struct ar0832_focuser_config)
+#define AR0832_FOCUSER_IOCTL_GET_CONFIG _IOR('o', 0x10, struct nv_focuser_config)
#define AR0832_FOCUSER_IOCTL_SET_POSITION _IOW('o', 0x11, __u32)
#define AR0832_IOCTL_GET_SENSOR_ID _IOR('o', 0x12, __u16)
+#define AR0832_FOCUSER_IOCTL_SET_CONFIG _IOW('o', 0x13, struct nv_focuser_config)
#define AR0832_SENSOR_ID_8141 0x1006
#define AR0832_SENSOR_ID_8140 0x3006
@@ -85,15 +87,6 @@ struct ar0832_stereo_region {
struct ar0832_point image_end;
};
-struct ar0832_focuser_config {
- __u32 settle_time;
- __u32 actuator_range;
- __u32 pos_low;
- __u32 pos_high;
- __u32 focal_length;
- __u32 fnumber;
- __u32 max_aperture;
-};
#ifdef __KERNEL__
struct ar0832_platform_data {
diff --git a/include/media/nvc_focus.h b/include/media/nvc_focus.h
index bed9df11a34a..e37d897d8323 100644
--- a/include/media/nvc_focus.h
+++ b/include/media/nvc_focus.h
@@ -33,6 +33,8 @@
#define NVC_FOCUS_CAP_VER2 2
#define NVC_FOCUS_CAP_VER 2 /* latest version */
+#define AF_POS_INVALID_VALUE INT_MAX
+
enum nvc_focus_sts {
NVC_FOCUS_STS_UNKNOWN = 1,
NVC_FOCUS_STS_NO_DEVICE,
@@ -52,12 +54,55 @@ struct nvc_focus_nvc {
struct nvc_focus_cap {
__u32 version;
- __u32 actuator_range;
+ __s32 actuator_range;
+ __u32 settle_time;
+ __s32 focus_macro;
+ __s32 focus_hyper;
+ __s32 focus_infinity;
+ __u32 slew_rate;
+ __u32 position_translate;
+} __packed;
+
+
+#define NV_FOCUSER_SET_MAX 10
+#define NV_FOCUSER_SET_DISTANCE_PAIR 16
+
+struct nv_focuser_set_dist_pairs {
+ __s32 fdn;
+ __s32 distance;
+} __packed;
+
+struct nv_focuser_set {
+ __s32 posture;
+ __s32 macro;
+ __s32 hyper;
+ __s32 inf;
+ __s32 hysteresis;
__u32 settle_time;
- __u32 focus_macro;
- __u32 focus_hyper;
- __u32 focus_infinity;
+ __s32 macro_offset;
+ __s32 inf_offset;
+ __u32 num_dist_pairs;
+ struct nv_focuser_set_dist_pairs
+ dist_pair[NV_FOCUSER_SET_DISTANCE_PAIR];
} __packed;
+struct nv_focuser_config {
+ __u32 focal_length;
+ __u32 fnumber;
+ __u32 max_aperture;
+ __s32 actuator_range;
+ __u32 settle_time;
+ __u32 range_ends_reversed;
+ __s32 pos_working_low;
+ __s32 pos_working_high;
+ __s32 pos_actual_low;
+ __s32 pos_actual_high;
+ __u32 slew_rate;
+ __u32 circle_of_confusion;
+ __u32 num_focuser_sets;
+ struct nv_focuser_set focuser_set[NV_FOCUSER_SET_MAX];
+} __packed;
+
+
#endif /* __NVC_FOCUS_H__ */
diff --git a/include/media/ov2710.h b/include/media/ov2710.h
index e3d43056d700..aeeaea8849e0 100644
--- a/include/media/ov2710.h
+++ b/include/media/ov2710.h
@@ -27,6 +27,7 @@
#define OV2710_IOCTL_SET_COARSE_TIME _IOW('o', 3, __u32)
#define OV2710_IOCTL_SET_GAIN _IOW('o', 4, __u16)
#define OV2710_IOCTL_GET_STATUS _IOR('o', 5, __u8)
+#define OV2710_IOCTL_SET_GROUP_HOLD _IOW('o', 6, struct ov2710_ae)
struct ov2710_mode {
int xres;
@@ -35,6 +36,16 @@ struct ov2710_mode {
__u32 coarse_time;
__u16 gain;
};
+
+struct ov2710_ae {
+ __u32 frame_length;
+ __u8 frame_length_enable;
+ __u32 coarse_time;
+ __u8 coarse_time_enable;
+ __s32 gain;
+ __u8 gain_enable;
+};
+
#ifdef __KERNEL__
struct ov2710_platform_data {
int (*power_on)(void);
diff --git a/include/media/ov5640.h b/include/media/ov5640.h
new file mode 100644
index 000000000000..edae5fe4b1a8
--- /dev/null
+++ b/include/media/ov5640.h
@@ -0,0 +1,64 @@
+/*
+ * ov5640.h - 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_H__
+#define __OV5640_H__
+
+#include <linux/ioctl.h> /* For IOCTL macros */
+
+#define OV5640_IOCTL_SET_SENSOR_MODE _IOW('o', 1, struct ov5640_mode)
+#define OV5640_IOCTL_GET_SENSOR_STATUS _IOR('o', 2, __u8)
+#define OV5640_IOCTL_GET_CONFIG _IOR('o', 3, struct ov5640_config)
+#define OV5640_IOCTL_SET_FPOSITION _IOW('o', 4, __u32)
+#define OV5640_IOCTL_POWER_LEVEL _IOW('o', 5, __u32)
+#define OV5640_IOCTL_GET_AF_STATUS _IOR('o', 6, __u8)
+#define OV5640_IOCTL_SET_AF_MODE _IOR('o', 7, __u8)
+
+#define OV5640_POWER_LEVEL_OFF 0
+#define OV5640_POWER_LEVEL_ON 1
+#define OV5640_POWER_LEVEL_SUS 2
+
+struct ov5640_mode {
+ int xres;
+ int yres;
+};
+
+struct ov5640_config {
+ __u32 settle_time;
+ __u32 pos_low;
+ __u32 pos_high;
+ float focal_length;
+ float fnumber;
+};
+
+enum {
+ OV5640_AF_INIFINITY,
+ OV5640_AF_TRIGGER,
+};
+
+#ifdef __KERNEL__
+struct ov5640_platform_data {
+ int (*power_on)(void);
+ int (*power_off)(void);
+
+};
+#endif /* __KERNEL__ */
+
+#endif /* __OV5640_H__ */
diff --git a/include/media/ov5650.h b/include/media/ov5650.h
index 5c4a87cfbe8d..a8f70a592d89 100644
--- a/include/media/ov5650.h
+++ b/include/media/ov5650.h
@@ -32,6 +32,7 @@
#define OV5650_IOCTL_SET_GROUP_HOLD _IOW('o', 8, struct ov5650_ae)
#define OV5650_IOCTL_SET_CAMERA_MODE _IOW('o', 10, __u32)
#define OV5650_IOCTL_SYNC_SENSORS _IOW('o', 11, __u32)
+#define OV5650_IOCTL_GET_SENSORDATA _IOR('o', 12, struct ov5650_sensordata)
/* OV5650 registers */
#define OV5650_SRM_GRUP_ACCESS (0x3212)
@@ -64,6 +65,11 @@ enum ov5650_test_pattern {
TEST_PATTERN_CHECKERBOARD
};
+struct ov5650_sensordata {
+ __u32 fuse_id_size;
+ __u8 fuse_id[16];
+};
+
struct ov5650_mode {
int xres;
int yres;
diff --git a/include/media/tegra_camera.h b/include/media/tegra_camera.h
index 8ee290758262..9dea1485781d 100644
--- a/include/media/tegra_camera.h
+++ b/include/media/tegra_camera.h
@@ -23,12 +23,14 @@ enum {
TEGRA_CAMERA_MODULE_ISP = 0,
TEGRA_CAMERA_MODULE_VI,
TEGRA_CAMERA_MODULE_CSI,
- TEGRA_CAMERA_MODULE_MAX,
+ TEGRA_CAMERA_MODULE_EMC,
+ TEGRA_CAMERA_MODULE_MAX
};
enum {
TEGRA_CAMERA_VI_CLK,
TEGRA_CAMERA_VI_SENSOR_CLK,
+ TEGRA_CAMERA_EMC_CLK
};
struct tegra_camera_clk_info {
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index ffa8aedd70f0..251a2f936727 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -426,6 +426,7 @@ struct station_parameters {
* @STATION_INFO_RX_BITRATE: @rxrate fields are filled
* @STATION_INFO_BSS_PARAM: @bss_param filled
* @STATION_INFO_CONNECTED_TIME: @connected_time filled
+ * @STATION_INFO_ASSOC_REQ_IES: @assoc_req_ies filled
*/
enum station_info_flags {
STATION_INFO_INACTIVE_TIME = 1<<0,
@@ -444,7 +445,8 @@ enum station_info_flags {
STATION_INFO_SIGNAL_AVG = 1<<13,
STATION_INFO_RX_BITRATE = 1<<14,
STATION_INFO_BSS_PARAM = 1<<15,
- STATION_INFO_CONNECTED_TIME = 1<<16
+ STATION_INFO_CONNECTED_TIME = 1<<16,
+ STATION_INFO_ASSOC_REQ_IES = 1<<17
};
/**
@@ -782,6 +784,15 @@ struct cfg80211_ssid {
};
/**
+ * enum cfg80211_scan_flag - scan request control flags
+ *
+ * @CFG80211_SCAN__FLAG_TX_ABORT: abort scan on pending transmit
+ */
+enum cfg80211_scan_flags {
+ CFG80211_SCAN_FLAG_TX_ABORT = NL80211_SCAN_FLAG_TX_ABORT,
+};
+
+/**
* struct cfg80211_scan_request - scan request description
*
* @ssids: SSIDs to scan for (active scan only)
@@ -790,6 +801,7 @@ struct cfg80211_ssid {
* @n_channels: total number of channels to scan
* @ie: optional information element(s) to add into Probe Request or %NULL
* @ie_len: length of ie in octets
+ * @flags: bit field of flags controlling operation
* @rates: bitmap of rates to advertise for each band
* @wiphy: the wiphy this was for
* @dev: the interface
@@ -801,6 +813,7 @@ struct cfg80211_scan_request {
u32 n_channels;
const u8 *ie;
size_t ie_len;
+ u32 flags;
u32 rates[IEEE80211_NUM_BANDS];
diff --git a/include/trace/events/nvhost.h b/include/trace/events/nvhost.h
index 4c44cdc99f98..6506af44e576 100644
--- a/include/trace/events/nvhost.h
+++ b/include/trace/events/nvhost.h
@@ -138,7 +138,74 @@ TRACE_EVENT(nvhost_channel_write_cmdbuf,
__entry->words, __entry->offset)
);
-TRACE_EVENT(nvhost_channel_write_cmdbuf_data,
+TRACE_EVENT(nvhost_cdma_end,
+ TP_PROTO(const char *name, int prio,
+ int hi_count, int med_count, int low_count),
+
+ TP_ARGS(name, prio, hi_count, med_count, low_count),
+
+ TP_STRUCT__entry(
+ __field(const char *, name)
+ __field(int, prio)
+ __field(int, hi_count)
+ __field(int, med_count)
+ __field(int, low_count)
+ ),
+
+ TP_fast_assign(
+ __entry->name = name;
+ __entry->prio = prio;
+ __entry->hi_count = hi_count;
+ __entry->med_count = med_count;
+ __entry->low_count = low_count;
+ ),
+
+ TP_printk("name=%s, prio=%d, hi=%d, med=%d, low=%d",
+ __entry->name, __entry->prio,
+ __entry->hi_count, __entry->med_count, __entry->low_count)
+);
+
+TRACE_EVENT(nvhost_cdma_flush,
+ TP_PROTO(const char *name, int timeout),
+
+ TP_ARGS(name, timeout),
+
+ TP_STRUCT__entry(
+ __field(const char *, name)
+ __field(int, timeout)
+ ),
+
+ TP_fast_assign(
+ __entry->name = name;
+ __entry->timeout = timeout;
+ ),
+
+ TP_printk("name=%s, timeout=%d",
+ __entry->name, __entry->timeout)
+);
+
+TRACE_EVENT(nvhost_cdma_push,
+ TP_PROTO(const char *name, u32 op1, u32 op2),
+
+ TP_ARGS(name, op1, op2),
+
+ TP_STRUCT__entry(
+ __field(const char *, name)
+ __field(u32, op1)
+ __field(u32, op2)
+ ),
+
+ TP_fast_assign(
+ __entry->name = name;
+ __entry->op1 = op1;
+ __entry->op2 = op2;
+ ),
+
+ TP_printk("name=%s, op1=%08x, op2=%08x",
+ __entry->name, __entry->op1, __entry->op2)
+);
+
+TRACE_EVENT(nvhost_cdma_push_gather,
TP_PROTO(const char *name, u32 mem_id,
u32 words, u32 offset, void *cmdbuf),
@@ -173,20 +240,30 @@ TRACE_EVENT(nvhost_channel_write_cmdbuf_data,
);
TRACE_EVENT(nvhost_channel_write_reloc,
- TP_PROTO(const char *name),
+ TP_PROTO(const char *name, u32 cmdbuf_mem, u32 cmdbuf_offset,
+ u32 target, u32 target_offset),
- TP_ARGS(name),
+ TP_ARGS(name, cmdbuf_mem, cmdbuf_offset, target, target_offset),
TP_STRUCT__entry(
__field(const char *, name)
+ __field(u32, cmdbuf_mem)
+ __field(u32, cmdbuf_offset)
+ __field(u32, target)
+ __field(u32, target_offset)
),
TP_fast_assign(
__entry->name = name;
+ __entry->cmdbuf_mem = cmdbuf_mem;
+ __entry->cmdbuf_offset = cmdbuf_offset;
+ __entry->target = target;
+ __entry->target_offset = target_offset;
),
- TP_printk("name=%s",
- __entry->name)
+ TP_printk("name=%s, cmdbuf_mem=%08x, cmdbuf_offset=%04x, target=%08x, target_offset=%04x",
+ __entry->name, __entry->cmdbuf_mem, __entry->cmdbuf_offset,
+ __entry->target, __entry->target_offset)
);
TRACE_EVENT(nvhost_channel_write_waitchks,
@@ -394,24 +471,32 @@ TRACE_EVENT(nvhost_channel_submitted,
);
TRACE_EVENT(nvhost_channel_submit_complete,
- TP_PROTO(const char *name, int count, u32 thresh),
+ TP_PROTO(const char *name, int count, u32 thresh,
+ int hi_count, int med_count, int low_count),
- TP_ARGS(name, count, thresh),
+ TP_ARGS(name, count, thresh, hi_count, med_count, low_count),
TP_STRUCT__entry(
__field(const char *, name)
__field(int, count)
__field(u32, thresh)
+ __field(int, hi_count)
+ __field(int, med_count)
+ __field(int, low_count)
),
TP_fast_assign(
__entry->name = name;
__entry->count = count;
__entry->thresh = thresh;
+ __entry->hi_count = hi_count;
+ __entry->med_count = med_count;
+ __entry->low_count = low_count;
),
- TP_printk("name=%s, count=%d, thresh=%d",
- __entry->name, __entry->count, __entry->thresh)
+ TP_printk("name=%s, count=%d, thresh=%d, hi=%d, med=%d, low=%d",
+ __entry->name, __entry->count, __entry->thresh,
+ __entry->hi_count, __entry->med_count, __entry->low_count)
);
TRACE_EVENT(nvhost_wait_cdma,
@@ -432,6 +517,51 @@ TRACE_EVENT(nvhost_wait_cdma,
TP_printk("name=%s, event=%d", __entry->name, __entry->eventid)
);
+TRACE_EVENT(nvhost_syncpt_update_min,
+ TP_PROTO(u32 id, u32 val),
+
+ TP_ARGS(id, val),
+
+ TP_STRUCT__entry(
+ __field(u32, id)
+ __field(u32, val)
+ ),
+
+ TP_fast_assign(
+ __entry->id = id;
+ __entry->val = val;
+ ),
+
+ TP_printk("id=%d, val=%d", __entry->id, __entry->val)
+);
+
+TRACE_EVENT(nvhost_syncpt_wait_check,
+ TP_PROTO(u32 mem_id, u32 offset, u32 syncpt_id, u32 thresh, u32 min),
+
+ TP_ARGS(mem_id, offset, syncpt_id, thresh, min),
+
+ TP_STRUCT__entry(
+ __field(u32, mem_id)
+ __field(u32, offset)
+ __field(u32, syncpt_id)
+ __field(u32, thresh)
+ __field(u32, min)
+ ),
+
+ TP_fast_assign(
+ __entry->mem_id = mem_id;
+ __entry->offset = offset;
+ __entry->syncpt_id = syncpt_id;
+ __entry->thresh = thresh;
+ __entry->min = min;
+ ),
+
+ TP_printk("mem_id=%08x, offset=%05x, id=%d, thresh=%d, current=%d",
+ __entry->mem_id, __entry->offset,
+ __entry->syncpt_id, __entry->thresh,
+ __entry->min)
+);
+
#endif /* _TRACE_NVHOST_H */
/* This part must be outside protection */
diff --git a/include/trace/events/nvmap.h b/include/trace/events/nvmap.h
new file mode 100644
index 000000000000..d42ae8d3c76f
--- /dev/null
+++ b/include/trace/events/nvmap.h
@@ -0,0 +1,304 @@
+/*
+ * include/trace/events/nvmap.h
+ *
+ * NvMap event logging to ftrace.
+ *
+ * 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 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.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM nvmap
+
+#if !defined(_TRACE_NVMAP_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_NVMAP_H
+
+#include "../../../drivers/video/tegra/nvmap/nvmap.h"
+#include <linux/nvmap.h>
+#include <linux/tracepoint.h>
+
+DECLARE_EVENT_CLASS(nvmap,
+ TP_PROTO(struct nvmap_client *client),
+ TP_ARGS(client),
+ TP_STRUCT__entry(
+ __field(struct nvmap_client *, client)
+ ),
+ TP_fast_assign(
+ __entry->client = client;
+ ),
+ TP_printk("client=%p, name=%s",
+ __entry->client, __entry->client->name)
+);
+
+DEFINE_EVENT(nvmap, nvmap_open,
+ TP_PROTO(struct nvmap_client *client),
+ TP_ARGS(client)
+);
+
+DEFINE_EVENT(nvmap, nvmap_release,
+ TP_PROTO(struct nvmap_client *client),
+ TP_ARGS(client)
+);
+
+TRACE_EVENT(nvmap_create_handle,
+ TP_PROTO(struct nvmap_client *client,
+ struct nvmap_handle *h,
+ u32 size,
+ struct nvmap_handle_ref *ref
+ ),
+
+ TP_ARGS(client, h, size, ref),
+
+ TP_STRUCT__entry(
+ __field(struct nvmap_client *, client)
+ __field(struct nvmap_handle *, h)
+ __field(u32, size)
+ __field(struct nvmap_handle_ref *, ref)
+ ),
+
+ TP_fast_assign(
+ __entry->client = client;
+ __entry->h = h;
+ __entry->size = size;
+ __entry->ref = ref;
+ ),
+
+ TP_printk("client=%p, name=%s, handle=%p, size=%d, ref=%p",
+ __entry->client, __entry->client->name,
+ __entry->h, __entry->size, __entry->ref)
+);
+
+TRACE_EVENT(nvmap_alloc_handle_id,
+ TP_PROTO(struct nvmap_client *client,
+ unsigned long handle_id,
+ u32 heap_mask,
+ u32 align,
+ u32 flags
+ ),
+
+ TP_ARGS(client, handle_id, heap_mask, align, flags),
+
+ TP_STRUCT__entry(
+ __field(struct nvmap_client *, client)
+ __field(unsigned long, handle_id)
+ __field(u32, heap_mask)
+ __field(u32, align)
+ __field(u32, flags)
+ ),
+
+ TP_fast_assign(
+ __entry->client = client;
+ __entry->handle_id = handle_id;
+ __entry->heap_mask = heap_mask;
+ __entry->align = align;
+ __entry->flags = flags;
+ ),
+
+ TP_printk("client=%p, id=0x%lx, heap_mask=0x%x, align=%d, flags=0x%x",
+ __entry->client, __entry->handle_id, __entry->heap_mask,
+ __entry->align, __entry->flags)
+);
+
+TRACE_EVENT(nvmap_free_handle_id,
+ TP_PROTO(struct nvmap_client *client,
+ unsigned long handle_id
+ ),
+
+ TP_ARGS(client, handle_id),
+
+ TP_STRUCT__entry(
+ __field(struct nvmap_client *, client)
+ __field(unsigned long, handle_id)
+ ),
+
+ TP_fast_assign(
+ __entry->client = client;
+ __entry->handle_id = handle_id;
+ ),
+
+ TP_printk("client=%p, id=0x%lx",
+ __entry->client, __entry->handle_id)
+);
+
+TRACE_EVENT(nvmap_duplicate_handle_id,
+ TP_PROTO(struct nvmap_client *client,
+ unsigned long handle_id,
+ struct nvmap_handle_ref *ref
+ ),
+
+ TP_ARGS(client, handle_id, ref),
+
+ TP_STRUCT__entry(
+ __field(struct nvmap_client *, client)
+ __field(unsigned long, handle_id)
+ __field(struct nvmap_handle_ref *, ref)
+ ),
+
+ TP_fast_assign(
+ __entry->client = client;
+ __entry->handle_id = handle_id;
+ __entry->ref = ref;
+ ),
+
+ TP_printk("client=%p, id=0x%lx, ref=%p",
+ __entry->client, __entry->handle_id, __entry->ref)
+);
+
+TRACE_EVENT(cache_maint,
+ TP_PROTO(struct nvmap_client *client,
+ struct nvmap_handle *h,
+ unsigned long start,
+ unsigned long end,
+ u32 op
+ ),
+
+ TP_ARGS(client, h, start, end, op),
+
+ TP_STRUCT__entry(
+ __field(struct nvmap_client *, client)
+ __field(struct nvmap_handle *, h)
+ __field(unsigned long, start)
+ __field(unsigned long, end)
+ __field(u32, op)
+ ),
+
+ TP_fast_assign(
+ __entry->client = client;
+ __entry->h = h;
+ __entry->start = start;
+ __entry->end = end;
+ __entry->op = op;
+ ),
+
+ TP_printk("client=%p, h=%p, start=0x%lx, end=0x%lx, op=%d",
+ __entry->client, __entry->h, __entry->start,
+ __entry->end, __entry->op)
+);
+
+TRACE_EVENT(nvmap_map_into_caller_ptr,
+ TP_PROTO(struct nvmap_client *client,
+ struct nvmap_handle *h,
+ u32 offset,
+ u32 length,
+ u32 flags
+ ),
+
+ TP_ARGS(client, h, offset, length, flags),
+
+ TP_STRUCT__entry(
+ __field(struct nvmap_client *, client)
+ __field(struct nvmap_handle *, h)
+ __field(u32, offset)
+ __field(u32, length)
+ __field(u32, flags)
+ ),
+
+ TP_fast_assign(
+ __entry->client = client;
+ __entry->h = h;
+ __entry->offset = offset;
+ __entry->length = length;
+ __entry->flags = flags;
+ ),
+
+ TP_printk("client=%p, h=%p, offset=%d, length=%d, flags=0x%x",
+ __entry->client, __entry->h, __entry->offset,
+ __entry->length, __entry->flags)
+);
+
+TRACE_EVENT(nvmap_ioctl_rw_handle,
+ TP_PROTO(struct nvmap_client *client,
+ struct nvmap_handle *h,
+ u32 is_read,
+ u32 offset,
+ unsigned long addr,
+ u32 mem_stride,
+ u32 user_stride,
+ u32 elem_size,
+ u32 count
+ ),
+
+ TP_ARGS(client, h, is_read, offset, addr, mem_stride,
+ user_stride, elem_size, count),
+
+ TP_STRUCT__entry(
+ __field(struct nvmap_client *, client)
+ __field(struct nvmap_handle *, h)
+ __field(u32, is_read)
+ __field(u32, offset)
+ __field(unsigned long, addr)
+ __field(u32, mem_stride)
+ __field(u32, user_stride)
+ __field(u32, elem_size)
+ __field(u32, count)
+ ),
+
+ TP_fast_assign(
+ __entry->client = client;
+ __entry->h = h;
+ __entry->is_read = is_read;
+ __entry->offset = offset;
+ __entry->addr = addr;
+ __entry->mem_stride = mem_stride;
+ __entry->user_stride = user_stride;
+ __entry->elem_size = elem_size;
+ __entry->count = count;
+ ),
+
+ TP_printk("client=%p, h=%p, is_read=%d, offset=%d, addr=0x%lx,"
+ "mem_stride=%d, user_stride=%d, elem_size=%d, count=%d",
+ __entry->client, __entry->h, __entry->is_read, __entry->offset,
+ __entry->addr, __entry->mem_stride, __entry->user_stride,
+ __entry->elem_size, __entry->count)
+);
+
+TRACE_EVENT(nvmap_ioctl_pinop,
+ TP_PROTO(struct nvmap_client *client,
+ u32 is_pin,
+ u32 count,
+ unsigned long *ids
+ ),
+
+ TP_ARGS(client, is_pin, count, ids),
+
+ TP_STRUCT__entry(
+ __field(struct nvmap_client *, client)
+ __field(u32, is_pin)
+ __field(u32, count)
+ __field(unsigned long *, ids)
+ __dynamic_array(unsigned long, ids, count)
+ ),
+
+ TP_fast_assign(
+ __entry->client = client;
+ __entry->is_pin = is_pin;
+ __entry->count = count;
+ __entry->ids = ids;
+ memcpy(__get_dynamic_array(ids), ids,
+ sizeof(unsigned long) * count);
+ ),
+
+ TP_printk("client=%p, is_pin=%d, count=%d, ids=[%s]",
+ __entry->client, __entry->is_pin, __entry->count,
+ __print_hex(__get_dynamic_array(ids), __entry->ids ?
+ sizeof(unsigned long) * __entry->count : 0))
+);
+
+
+#endif /* _TRACE_NVMAP_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/include/trace/events/power.h b/include/trace/events/power.h
index 9c9699a2b457..5b503e9b661c 100644
--- a/include/trace/events/power.h
+++ b/include/trace/events/power.h
@@ -41,6 +41,11 @@ DEFINE_EVENT(cpu, cpu_idle,
#define PWR_EVENT_EXIT -1
enum {
+ CPU_SUSPEND_START,
+ CPU_SUSPEND_DONE
+};
+
+enum {
POWER_CPU_UP_START,
POWER_CPU_UP_DONE,
POWER_CPU_DOWN_START,
@@ -59,6 +64,23 @@ enum {
#endif
+TRACE_EVENT(cpu_suspend,
+
+ TP_PROTO(unsigned int state),
+
+ TP_ARGS(state),
+
+ TP_STRUCT__entry(
+ __field(u32, state)
+ ),
+
+ TP_fast_assign(
+ __entry->state = state;
+ ),
+
+ TP_printk("state=%lu", (unsigned long)__entry->state)
+);
+
TRACE_EVENT(cpu_hotplug,
TP_PROTO(unsigned int cpu_id, int state),
diff --git a/include/video/tegra_dc_ext.h b/include/video/tegra_dc_ext.h
index f46074b1e559..8f9d0423f516 100644
--- a/include/video/tegra_dc_ext.h
+++ b/include/video/tegra_dc_ext.h
@@ -59,6 +59,7 @@
#define TEGRA_DC_EXT_FLIP_FLAG_INVERT_V (1 << 1)
#define TEGRA_DC_EXT_FLIP_FLAG_TILED (1 << 2)
#define TEGRA_DC_EXT_FLIP_FLAG_CURSOR (1 << 3)
+#define TEGRA_DC_EXT_FLIP_FLAG_GLOBAL_ALPHA (1 << 4)
struct tegra_dc_ext_flip_windowattr {
__s32 index;
@@ -91,8 +92,10 @@ struct tegra_dc_ext_flip_windowattr {
__u32 buff_id_u;
__u32 buff_id_v;
__u32 flags;
+ __u8 global_alpha; /* requires TEGRA_DC_EXT_FLIP_FLAG_GLOBAL_ALPHA */
/* Leave some wiggle room for future expansion */
- __u32 pad[5];
+ __u8 pad1[3];
+ __u32 pad2[4];
};
#define TEGRA_DC_EXT_FLIP_N_WINDOWS 3
@@ -208,6 +211,11 @@ struct tegra_dc_ext_status {
__u32 pad[3];
};
+struct tegra_dc_ext_feature {
+ __u32 length;
+ __u32 *entries;
+};
+
#define TEGRA_DC_EXT_SET_NVMAP_FD \
_IOW('D', 0x00, __s32)
@@ -244,6 +252,9 @@ struct tegra_dc_ext_status {
#define TEGRA_DC_EXT_SET_LUT \
_IOW('D', 0x0A, struct tegra_dc_ext_lut)
+#define TEGRA_DC_EXT_GET_FEATURES \
+ _IOW('D', 0x0B, struct tegra_dc_ext_feature)
+
enum tegra_dc_ext_control_output_type {
TEGRA_DC_EXT_DSI,
TEGRA_DC_EXT_LVDS,
diff --git a/kernel/gcov/gcc_3_4.c b/kernel/gcov/gcc_3_4.c
index d753d1152b7b..bc78336bc345 100644
--- a/kernel/gcov/gcc_3_4.c
+++ b/kernel/gcov/gcc_3_4.c
@@ -466,8 +466,12 @@ int gcov_iter_write(struct gcov_iterator *iter, struct seq_file *seq)
rc = seq_write_gcov_u32(seq, GCOV_TAG_FUNCTION);
break;
case RECORD_FUNCTON_TAG_LEN:
+#ifdef GCOV_FN_INFO_HAS_NAME_FIELD
rc = seq_write_gcov_u32(seq, GCOV_TAG_FUNCTION_LENGTH +
(sizeof_str(get_func(iter)->name)));
+#else
+ rc = seq_write_gcov_u32(seq, GCOV_TAG_FUNCTION_LENGTH);
+#endif
break;
case RECORD_FUNCTION_IDENT:
rc = seq_write_gcov_u32(seq, get_func(iter)->ident);
@@ -479,11 +483,19 @@ int gcov_iter_write(struct gcov_iterator *iter, struct seq_file *seq)
rc = seq_write_gcov_u32(seq, get_func(iter)->cfg_checksum);
break;
case RECORD_FUNCTION_NAME_LEN:
+#ifdef GCOV_FN_INFO_HAS_NAME_FIELD
rc = seq_write_gcov_u32(seq,
(sizeof_str(get_func(iter)->name) - 1));
+#else
+ rc = 0;
+#endif
break;
case RECORD_FUNCTION_NAME:
+#ifdef GCOV_FN_INFO_HAS_NAME_FIELD
rc = seq_write_gcov_str(seq, get_func(iter)->name);
+#else
+ rc = 0;
+#endif
break;
case RECORD_COUNT_TAG:
rc = seq_write_gcov_u32(seq,
diff --git a/kernel/gcov/gcov.h b/kernel/gcov/gcov.h
index 040c6980df0d..8c5130a5c1b5 100644
--- a/kernel/gcov/gcov.h
+++ b/kernel/gcov/gcov.h
@@ -17,7 +17,14 @@
#include <linux/types.h>
/*
- * Profiling data types used for gcc 3.4 and above - these are defined by
+ * GCC 4.6 drops the 'name' field from 'struct gcov_fn_info'.
+ */
+#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6)
+#define GCOV_FN_INFO_HAS_NAME_FIELD
+#endif
+
+/*
+ * Profiling data types used for at least gcc 4.4 and 4.6 - these are defined by
* gcc and need to be kept as close to the original definition as possible to
* remain compatible.
*/
@@ -77,7 +84,9 @@ struct gcov_fn_info {
unsigned int lineno_checksum;
unsigned int cfg_checksum;
unsigned int dc_offset;
+#ifdef GCOV_FN_INFO_HAS_NAME_FIELD
const char *name;
+#endif
unsigned int n_ctrs[0];
};
diff --git a/kernel/sched.c b/kernel/sched.c
index f6cf5cbc64ba..bb40a1bca717 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -472,6 +472,11 @@ struct rq {
#endif
int skip_clock_update;
+ /* time-based average load */
+ u64 nr_last_stamp;
+ unsigned int ave_nr_running;
+ seqcount_t ave_seqcnt;
+
/* capture load from *all* tasks on this cpu: */
struct load_weight load;
unsigned long nr_load_updates;
@@ -1756,14 +1761,49 @@ static const struct sched_class rt_sched_class;
#include "sched_stats.h"
+/* 27 ~= 134217728ns = 134.2ms
+ * 26 ~= 67108864ns = 67.1ms
+ * 25 ~= 33554432ns = 33.5ms
+ * 24 ~= 16777216ns = 16.8ms
+ */
+#define NR_AVE_PERIOD_EXP 27
+#define NR_AVE_SCALE(x) ((x) << FSHIFT)
+#define NR_AVE_PERIOD (1 << NR_AVE_PERIOD_EXP)
+#define NR_AVE_DIV_PERIOD(x) ((x) >> NR_AVE_PERIOD_EXP)
+
+static inline unsigned int do_avg_nr_running(struct rq *rq)
+{
+ s64 nr, deltax;
+ unsigned int ave_nr_running = rq->ave_nr_running;
+
+ deltax = rq->clock_task - rq->nr_last_stamp;
+ nr = NR_AVE_SCALE(rq->nr_running);
+
+ if (deltax > NR_AVE_PERIOD)
+ ave_nr_running = nr;
+ else
+ ave_nr_running +=
+ NR_AVE_DIV_PERIOD(deltax * (nr - ave_nr_running));
+
+ return ave_nr_running;
+}
+
static void inc_nr_running(struct rq *rq)
{
+ write_seqcount_begin(&rq->ave_seqcnt);
+ rq->ave_nr_running = do_avg_nr_running(rq);
+ rq->nr_last_stamp = rq->clock_task;
rq->nr_running++;
+ write_seqcount_end(&rq->ave_seqcnt);
}
static void dec_nr_running(struct rq *rq)
{
+ write_seqcount_begin(&rq->ave_seqcnt);
+ rq->ave_nr_running = do_avg_nr_running(rq);
+ rq->nr_last_stamp = rq->clock_task;
rq->nr_running--;
+ write_seqcount_end(&rq->ave_seqcnt);
}
static void set_load_weight(struct task_struct *p)
@@ -3255,6 +3295,33 @@ unsigned long nr_iowait(void)
return sum;
}
+unsigned long avg_nr_running(void)
+{
+ unsigned long i, sum = 0;
+ unsigned int seqcnt, ave_nr_running;
+
+ for_each_online_cpu(i) {
+ struct rq *q = cpu_rq(i);
+
+ /*
+ * Update average to avoid reading stalled value if there were
+ * no run-queue changes for a long time. On the other hand if
+ * the changes are happening right now, just read current value
+ * directly.
+ */
+ seqcnt = read_seqcount_begin(&q->ave_seqcnt);
+ ave_nr_running = do_avg_nr_running(q);
+ if (read_seqcount_retry(&q->ave_seqcnt, seqcnt)) {
+ read_seqcount_begin(&q->ave_seqcnt);
+ ave_nr_running = q->ave_nr_running;
+ }
+
+ sum += ave_nr_running;
+ }
+
+ return sum;
+}
+
unsigned long nr_iowait_cpu(int cpu)
{
struct rq *this = cpu_rq(cpu);
diff --git a/kernel/sched_debug.c b/kernel/sched_debug.c
index a6710a112b4f..6371af0e4612 100644
--- a/kernel/sched_debug.c
+++ b/kernel/sched_debug.c
@@ -264,6 +264,9 @@ static void print_cpu(struct seq_file *m, int cpu)
SEQ_printf(m, " .%-30s: %Ld.%06ld\n", #x, SPLIT_NS(rq->x))
P(nr_running);
+ SEQ_printf(m, " .%-30s: %d.%03d \n", "ave_nr_running",
+ rq->ave_nr_running / FIXED_1,
+ ((rq->ave_nr_running % FIXED_1) * 1000) / FIXED_1);
SEQ_printf(m, " .%-30s: %lu\n", "load",
rq->load.weight);
P(nr_switches);
diff --git a/kernel/sched_rt.c b/kernel/sched_rt.c
index af1177858be3..046f429be33d 100644
--- a/kernel/sched_rt.c
+++ b/kernel/sched_rt.c
@@ -497,6 +497,7 @@ balanced:
* runtime - in which case borrowing doesn't make sense.
*/
rt_rq->rt_runtime = RUNTIME_INF;
+ rt_rq->rt_throttled = 0;
raw_spin_unlock(&rt_rq->rt_runtime_lock);
raw_spin_unlock(&rt_b->rt_runtime_lock);
}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 9fab144cc9f5..8624f27441f2 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -718,6 +718,10 @@ enum {
* about us leaving the channel and stop all associated STA interfaces
* @SCAN_ENTER_OPER_CHANNEL: Enter the operating channel again, notify the
* AP about us being back and restart all associated STA interfaces
+ * @SCAN_ABORT: Abnormally terminate the scan operation, set only when
+ * on the operating channel
+ * @SCAN_ENTER_OPER_CHANNEL_ABORT: Return to the operating channel then
+ * terminate the scan operation
*/
enum mac80211_scan_state {
SCAN_DECISION,
@@ -725,6 +729,8 @@ enum mac80211_scan_state {
SCAN_SEND_PROBE,
SCAN_LEAVE_OPER_CHANNEL,
SCAN_ENTER_OPER_CHANNEL,
+ SCAN_ABORT,
+ SCAN_ENTER_OPER_CHANNEL_ABORT,
};
struct ieee80211_local {
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 6f09eca01112..4aa2cec04f31 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -477,6 +477,7 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local,
unsigned long min_beacon_int = 0;
struct ieee80211_sub_if_data *sdata;
struct ieee80211_channel *next_chan;
+ enum mac80211_scan_state next_scan_state;
/*
* check if at least one STA interface is associated,
@@ -512,13 +513,21 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local,
/* We're currently on operating channel. */
if (next_chan == local->oper_channel)
/* We don't need to move off of operating channel. */
- local->next_scan_state = SCAN_SET_CHANNEL;
- else
+ next_scan_state = SCAN_SET_CHANNEL;
+ else {
/*
* We do need to leave operating channel, as next
- * scan is somewhere else.
+ * scan is somewhere else, unless
+ * there is pending traffic and the scan request is
+ * marked to abort when this happens
*/
- local->next_scan_state = SCAN_LEAVE_OPER_CHANNEL;
+ if (associated && !tx_empty &&
+ (local->scan_req->flags &
+ CFG80211_SCAN_FLAG_TX_ABORT))
+ next_scan_state = SCAN_ABORT;
+ else
+ next_scan_state = SCAN_LEAVE_OPER_CHANNEL;
+ }
} else {
/*
* we're currently scanning a different channel, let's
@@ -547,12 +556,24 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local,
usecs_to_jiffies(min_beacon_int * 1024) *
local->hw.conf.listen_interval);
- if (associated && ( !tx_empty || bad_latency ||
- listen_int_exceeded))
- local->next_scan_state = SCAN_ENTER_OPER_CHANNEL;
+ if (associated && !tx_empty) {
+ if (unlikely(local->scan_req->flags &
+ CFG80211_SCAN_FLAG_TX_ABORT)) {
+ /*
+ * Scan request is marked to abort when there
+ * is outbound traffic. Mark state to return
+ * the operating channel and then abort. This
+ * happens as soon as possible.
+ */
+ next_scan_state = SCAN_ENTER_OPER_CHANNEL_ABORT;
+ } else
+ next_scan_state = SCAN_ENTER_OPER_CHANNEL;
+ } else if (associated && (bad_latency || listen_int_exceeded))
+ next_scan_state = SCAN_ENTER_OPER_CHANNEL;
else
- local->next_scan_state = SCAN_SET_CHANNEL;
+ next_scan_state = SCAN_SET_CHANNEL;
}
+ local->next_scan_state = next_scan_state;
*next_delay = 0;
}
@@ -596,8 +617,13 @@ static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *loca
*/
ieee80211_offchannel_return(local, true, false);
- *next_delay = HZ / 5;
- local->next_scan_state = SCAN_DECISION;
+ if (local->next_scan_state == SCAN_ENTER_OPER_CHANNEL) {
+ *next_delay = HZ / 5;
+ local->next_scan_state = SCAN_DECISION;
+ } else {
+ *next_delay = 0;
+ local->next_scan_state = SCAN_ABORT;
+ }
}
static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
@@ -741,11 +767,15 @@ void ieee80211_scan_work(struct work_struct *work)
ieee80211_scan_state_send_probe(local, &next_delay);
break;
case SCAN_LEAVE_OPER_CHANNEL:
+ case SCAN_ENTER_OPER_CHANNEL_ABORT:
ieee80211_scan_state_leave_oper_channel(local, &next_delay);
break;
case SCAN_ENTER_OPER_CHANNEL:
ieee80211_scan_state_enter_oper_channel(local, &next_delay);
break;
+ case SCAN_ABORT:
+ aborted = true;
+ goto out_complete;
}
} while (next_delay == 0);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index fb18bb4dea7a..84400e3a17b6 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -131,6 +131,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
[NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 },
[NL80211_ATTR_IE] = { .type = NLA_BINARY,
.len = IEEE80211_MAX_DATA_LEN },
+ [NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 },
[NL80211_ATTR_SCAN_FREQUENCIES] = { .type = NLA_NESTED },
[NL80211_ATTR_SCAN_SSIDS] = { .type = NLA_NESTED },
@@ -2236,7 +2237,7 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
}
nla_nest_end(msg, sinfoattr);
- if (sinfo->assoc_req_ies)
+ if (sinfo->filled & STATION_INFO_ASSOC_REQ_IES)
NLA_PUT(msg, NL80211_ATTR_IE, sinfo->assoc_req_ies_len,
sinfo->assoc_req_ies);
@@ -3457,6 +3458,10 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
request->ie_len);
}
+ if (info->attrs[NL80211_ATTR_SCAN_FLAGS])
+ request->flags = nla_get_u32(
+ info->attrs[NL80211_ATTR_SCAN_FLAGS]);
+
for (i = 0; i < IEEE80211_NUM_BANDS; i++)
if (wiphy->bands[i])
request->rates[i] =
@@ -6158,6 +6163,8 @@ static int nl80211_add_scan_req(struct sk_buff *msg,
if (req->ie)
NLA_PUT(msg, NL80211_ATTR_IE, req->ie_len, req->ie);
+ NLA_PUT_U8(msg, NL80211_ATTR_SCAN_FLAGS, req->flags);
+
return 0;
nla_put_failure:
return -ENOBUFS;
diff --git a/security/tf_driver/Makefile b/security/tf_driver/Makefile
index dfadb7d97406..5c48f626f5d8 100644
--- a/security/tf_driver/Makefile
+++ b/security/tf_driver/Makefile
@@ -21,7 +21,7 @@
# debug options
#EXTRA_CFLAGS += -O0 -DDEBUG -D_DEBUG -DCONFIG_TF_DRIVER_DEBUG_SUPPORT
EXTRA_CFLAGS += -DNDEBUG
-EXTRA_CFLAGS += -DLINUX -DCONFIG_TF_TRUSTZONE -DCONFIG_TFN
+EXTRA_CFLAGS += -DLINUX -DCONFIG_TF_TRUSTZONE -DCONFIG_TFN -DCONFIG_SECURE_TRACES
ifdef S_VERSION_BUILD
EXTRA_CFLAGS += -DS_VERSION_BUILD=$(S_VERSION_BUILD)
diff --git a/security/tf_driver/s_version.h b/security/tf_driver/s_version.h
index ba4d48c6f417..d812cdca75df 100644
--- a/security/tf_driver/s_version.h
+++ b/security/tf_driver/s_version.h
@@ -33,12 +33,12 @@
*/
#define S_VERSION_OS "A" /* "A" for all Android */
-#define S_VERSION_PLATFORM "A" /* "A" for Tegra2 */
+#define S_VERSION_PLATFORM "B" /* "B" for Tegra3 */
/*
* This version number must be updated for each new release
*/
-#define S_VERSION_MAIN "01.07"
+#define S_VERSION_MAIN "01.08"
/*
* If this is a patch or engineering version use the following
diff --git a/security/tf_driver/tf_comm_tz.c b/security/tf_driver/tf_comm_tz.c
index 4c89de84accf..4628f24f3cf2 100644
--- a/security/tf_driver/tf_comm_tz.c
+++ b/security/tf_driver/tf_comm_tz.c
@@ -194,6 +194,20 @@ static inline void tf_smc_nyield(void)
tf_smc_generic_call(&generic_smc);
}
+#ifdef CONFIG_SECURE_TRACES
+static void tf_print_secure_traces(struct tf_comm *comm)
+{
+ spin_lock(&(comm->lock));
+ if (comm->l1_buffer->traces_status != 0) {
+ if (comm->l1_buffer->traces_status > 1)
+ pr_info("TF : traces lost...\n");
+ pr_info("TF : %s", comm->l1_buffer->traces_buffer);
+ comm->l1_buffer->traces_status = 0;
+ }
+ spin_unlock(&(comm->lock));
+}
+#endif
+
/* Yields the Secure World */
int tf_schedule_secure_world(struct tf_comm *comm)
{
@@ -202,6 +216,10 @@ int tf_schedule_secure_world(struct tf_comm *comm)
/* yield to the Secure World */
tf_smc_nyield();
+#ifdef CONFIG_SECURE_TRACES
+ tf_print_secure_traces(comm);
+#endif
+
return 0;
}
diff --git a/security/tf_driver/tf_device.c b/security/tf_driver/tf_device.c
index 5d5f3c63ce88..8f31bf35f90a 100644
--- a/security/tf_driver/tf_device.c
+++ b/security/tf_driver/tf_device.c
@@ -87,7 +87,7 @@ static long tf_device_ioctl(
/*
* Implements the device shutdown callback.
*/
-static int tf_device_shutdown(void);
+static void tf_device_shutdown(void);
/*
@@ -99,7 +99,7 @@ static int tf_device_suspend(void);
/*
* Implements the device resume callback.
*/
-static int tf_device_resume(void);
+static void tf_device_resume(void);
/*---------------------------------------------------------------------------
@@ -762,11 +762,10 @@ exit:
/*----------------------------------------------------------------------------*/
-static int tf_device_shutdown(void)
+static void tf_device_shutdown(void)
{
-
- return tf_power_management(&g_tf_dev.sm,
- TF_POWER_OPERATION_SHUTDOWN);
+ if (0 > tf_power_management(&g_tf_dev.sm, TF_POWER_OPERATION_SHUTDOWN))
+ dprintk(KERN_ERR "tf_device_shutdown failing\n");
}
/*----------------------------------------------------------------------------*/
@@ -781,10 +780,10 @@ static int tf_device_suspend(void)
/*----------------------------------------------------------------------------*/
-static int tf_device_resume(void)
+static void tf_device_resume(void)
{
- return tf_power_management(&g_tf_dev.sm,
- TF_POWER_OPERATION_RESUME);
+ if (0 > tf_power_management(&g_tf_dev.sm, TF_POWER_OPERATION_RESUME))
+ dprintk(KERN_ERR "tf_device_resume failing\n");
}
diff --git a/security/tf_driver/tf_protocol.h b/security/tf_driver/tf_protocol.h
index 403df8ec8ef5..b264f04c4454 100644
--- a/security/tf_driver/tf_protocol.h
+++ b/security/tf_driver/tf_protocol.h
@@ -659,6 +659,10 @@ struct tf_l1_shared_buffer {
#ifdef CONFIG_TF_ZEBRA
u8 rpc_trace_buffer[140];
u8 rpc_cus_buffer[180];
+ #elif CONFIG_SECURE_TRACES
+ u32 traces_status;
+ u8 traces_buffer[140];
+ u8 reserved3[176];
#else
u8 reserved3[320];
#endif
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 2eaef5b52e08..d80b7bbff2e8 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -35,8 +35,7 @@ snd-soc-stac9766-objs := stac9766.o
snd-soc-tlv320aic23-objs := tlv320aic23.o
snd-soc-tlv320aic26-objs := tlv320aic26.o
snd-soc-tlv320aic3x-objs := tlv320aic3x.o
-snd-soc-tlv320aic326x-objs := tlv320aic326x.o tlv320aic326x_minidsp_config.o
-snd-soc-tlv320aic326x-objs += tlv320aic326x_mini-dsp.o aic326x_tiload.o
+snd-soc-tlv320aic326x-objs := tlv320aic326x.o
snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o
snd-soc-tlv320dac33-objs := tlv320dac33.o
snd-soc-twl4030-objs := twl4030.o
diff --git a/sound/soc/codecs/aic326x_tiload.c b/sound/soc/codecs/aic326x_tiload.c
index 00aa4d4ce7d7..07615dc5ebd7 100644
--- a/sound/soc/codecs/aic326x_tiload.c
+++ b/sound/soc/codecs/aic326x_tiload.c
@@ -61,7 +61,8 @@ static void aic3262_dump_page(struct i2c_client *i2c, u8 page);
/* externs */
extern int aic3262_change_page(struct snd_soc_codec *codec, u8 new_page);
extern int aic3262_change_book(struct snd_soc_codec *codec, u8 new_book);
-extern int aic3262_write(struct snd_soc_codec *codec, u16 reg, u8 value);
+extern int aic3262_write(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int value);
int aic3262_driver_init(struct snd_soc_codec *codec);
/************** Dynamic aic3262 driver, TI LOAD support ***************/
@@ -236,7 +237,7 @@ static ssize_t tiload_write(struct file *file, const char __user * buf,
return i2c_master_send(i2c, wr_data, count);
}
-static int tiload_ioctl( struct file *filp,
+static long tiload_ioctl(struct file *filp,
unsigned int cmd, unsigned long arg)
{
int num = 0;
diff --git a/sound/soc/codecs/base_main_Rate48_pps_driver.h b/sound/soc/codecs/base_main_Rate48_pps_driver.h
index 4d6f227cc42e..dff91858940e 100644
--- a/sound/soc/codecs/base_main_Rate48_pps_driver.h
+++ b/sound/soc/codecs/base_main_Rate48_pps_driver.h
@@ -16,17 +16,6 @@ static control base_speaker_SRS_VOLUME_controls[] = {
static char * base_speaker_SRS_VOLUME_control_names[] = {
};
-/*//INSTRUCTIONS & COEFFICIENTS
-typedef struct {
- u8 reg_off;
- u8 reg_val;
-} reg_value;*/
-
-static char * base_speaker_SRS_REG_Section_names[] = {
- "miniDSP_A_reg_values",
- "miniDSP_D_reg_values",
-};
-
reg_value base_speaker_SRS_REG_init_Section_program[] = {
{ 0,0x0},
{ 0x7F,0x00},
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
index e2ad10d2deaa..b2b31f912b74 100644
--- a/sound/soc/codecs/max98088.c
+++ b/sound/soc/codecs/max98088.c
@@ -57,6 +57,8 @@ struct max98088_priv {
unsigned int extmic_mode;
int irq;
struct snd_soc_jack *headset_jack;
+ unsigned int jk_sns;
+ int jack_report;
};
static const u8 max98088_reg[M98088_REG_CNT] = {
@@ -1968,19 +1970,28 @@ static void max98088_handle_pdata(struct snd_soc_codec *codec)
int max98088_report_jack(struct snd_soc_codec *codec)
{
struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
- unsigned int value;
- int jack_report = 0;
+ unsigned int jk_sns_curr;
+ int jack_report_curr = 0;
/* Read the Jack Status Register*/
- value = snd_soc_read(codec, M98088_REG_02_JACK_STAUS);
+ jk_sns_curr = (snd_soc_read(codec, M98088_REG_02_JACK_STAUS))
+ & (M98088_JKSNS_7 | M98088_JKSNS_6);
+
+ if (max98088->jk_sns == M98088_NONE && jk_sns_curr == M98088_HP)
+ jack_report_curr = SND_JACK_HEADPHONE;
+ else if (max98088->jk_sns == M98088_NONE && jk_sns_curr == M98088_HS)
+ jack_report_curr = SND_JACK_HEADSET;
+ else if ((max98088->jk_sns == M98088_HP || max98088->jk_sns == M98088_HS)
+ && jk_sns_curr == M98088_NONE)
+ jack_report_curr = 0;
+ else
+ jack_report_curr = max98088->jack_report;
- if ((value & M98088_JKSNS_7) == 0)
- jack_report |= SND_JACK_HEADPHONE;
- if (value & M98088_JKSNS_6)
- jack_report |= SND_JACK_MICROPHONE;
+ max98088->jack_report = jack_report_curr;
+ max98088->jk_sns = jk_sns_curr;
snd_soc_jack_report(max98088->headset_jack,
- jack_report, SND_JACK_HEADSET);
+ jack_report_curr, SND_JACK_HEADSET);
return 0;
}
@@ -2001,6 +2012,8 @@ int max98088_headset_detect(struct snd_soc_codec *codec,
{
struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
max98088->headset_jack = jack;
+ max98088->jk_sns = M98088_NONE;
+ max98088->jack_report = 0;
if (max98088->irq) {
if (type & SND_JACK_HEADSET) {
diff --git a/sound/soc/codecs/max98088.h b/sound/soc/codecs/max98088.h
index cf4b04d2d07a..81ccf4b4caee 100644
--- a/sound/soc/codecs/max98088.h
+++ b/sound/soc/codecs/max98088.h
@@ -222,6 +222,11 @@
#define M98088_BYTE1(w) ((w >> 8) & 0xff)
#define M98088_BYTE0(w) (w & 0xff)
+/* HeadPhone and HeadSet detection Bitmasks */
+#define M98088_HP 0
+#define M98088_HS M98088_JKSNS_6
+#define M98088_NONE (M98088_JKSNS_7 | M98088_JKSNS_6)
+
int max98088_headset_detect(struct snd_soc_codec *codec,
struct snd_soc_jack *jack, enum snd_jack_types type);
diff --git a/sound/soc/codecs/rt5639.c b/sound/soc/codecs/rt5639.c
index e8841e0d6e4d..13190e21404b 100644
--- a/sound/soc/codecs/rt5639.c
+++ b/sound/soc/codecs/rt5639.c
@@ -105,6 +105,18 @@ static int rt5639_reg_init(struct snd_soc_codec *codec)
}
#endif
+static int rt5639_index_sync(struct snd_soc_codec *codec)
+{
+ int i;
+
+ for (i = 0; i < RT5639_INIT_REG_LEN; i++)
+ if (RT5639_PRIV_INDEX == init_list[i].reg ||
+ RT5639_PRIV_DATA == init_list[i].reg)
+ snd_soc_write(codec, init_list[i].reg,
+ init_list[i].val);
+ return 0;
+}
+
static const u16 rt5639_reg[RT5639_VENDOR_ID2 + 1] = {
[RT5639_RESET] = 0x0008,
[RT5639_SPK_VOL] = 0xc8c8,
@@ -1198,8 +1210,6 @@ static int spk_event(struct snd_soc_dapm_widget *w,
static int hp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct snd_soc_codec *codec = w->codec;
-
switch (event) {
case SND_SOC_DAPM_POST_PMU:
printk("hp_event --SND_SOC_DAPM_POST_PMU\n");
@@ -2215,7 +2225,9 @@ static int rt5639_set_bias_level(struct snd_soc_codec *codec,
RT5639_PWR_FV1 | RT5639_PWR_FV2,
RT5639_PWR_FV1 | RT5639_PWR_FV2);
codec->cache_only = false;
+ codec->cache_sync = 1;
snd_soc_cache_sync(codec);
+ rt5639_index_sync(codec);
}
break;
@@ -2313,13 +2325,23 @@ static int rt5639_remove(struct snd_soc_codec *codec)
#ifdef CONFIG_PM
static int rt5639_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
+ rt5639_reset(codec);
rt5639_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
static int rt5639_resume(struct snd_soc_codec *codec)
{
+ int ret = 0 ;
+
+ codec->cache_sync = 1;
+ ret = snd_soc_cache_sync(codec);
+ if (ret) {
+ dev_err(codec->dev,"Failed to sync cache: %d\n", ret);
+ return ret;
+ }
rt5639_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
return 0;
}
#else
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
index cd84ed0858ac..49256e2d151d 100644
--- a/sound/soc/codecs/rt5640.c
+++ b/sound/soc/codecs/rt5640.c
@@ -25,7 +25,7 @@
#include <sound/tlv.h>
#include "rt5640.h"
-#if (CONFIG_SND_SOC_RT5642_MODULE | CONFIG_SND_SOC_RT5642)
+#if defined(CONFIG_SND_SOC_RT5642_MODULE) || defined(CONFIG_SND_SOC_RT5642)
#include "rt5640-dsp.h"
#endif
@@ -106,6 +106,18 @@ static int rt5640_reg_init(struct snd_soc_codec *codec)
}
#endif
+static int rt5640_index_sync(struct snd_soc_codec *codec)
+{
+ int i;
+
+ for (i = 0; i < RT5640_INIT_REG_LEN; i++)
+ if (RT5640_PRIV_INDEX == init_list[i].reg ||
+ RT5640_PRIV_DATA == init_list[i].reg)
+ snd_soc_write(codec, init_list[i].reg,
+ init_list[i].val);
+ return 0;
+}
+
static const u16 rt5640_reg[RT5640_VENDOR_ID2 + 1] = {
[RT5640_RESET] = 0x000c,
[RT5640_SPK_VOL] = 0xc8c8,
@@ -1179,8 +1191,6 @@ static int spk_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
- static unsigned int spkl_out_enable;
- static unsigned int spkr_out_enable;
switch (event) {
case SND_SOC_DAPM_POST_PMU:
@@ -1206,9 +1216,6 @@ static int spk_event(struct snd_soc_dapm_widget *w,
static int hp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct snd_soc_codec *codec = w->codec;
- static unsigned int hp_out_enable;
-
switch (event) {
case SND_SOC_DAPM_POST_PMU:
pr_info("hp_event --SND_SOC_DAPM_POST_PMU\n");
@@ -1820,9 +1827,8 @@ static int get_sdp_info(struct snd_soc_codec *codec, int dai_id)
ret |= RT5640_U_IF3;
break;
-#if (CONFIG_SND_SOC_RT5643_MODULE | CONFIG_SND_SOC_RT5643 | \
- CONFIG_SND_SOC_RT5646_MODULE | CONFIG_SND_SOC_RT5646)
-
+#if defined(CONFIG_SND_SOC_RT5643_MODULE) || defined(CONFIG_SND_SOC_RT5643) || \
+ defined(CONFIG_SND_SOC_RT5646_MODULE) || defined(CONFIG_SND_SOC_RT5646)
case RT5640_AIF3:
if (val == RT5640_IF_312 || val == RT5640_IF_321)
ret |= RT5640_U_IF1;
@@ -1922,8 +1928,8 @@ static int rt5640_hw_params(struct snd_pcm_substream *substream,
RT5640_I2S_DL_MASK, val_len);
snd_soc_update_bits(codec, RT5640_ADDA_CLK1, mask_clk, val_clk);
}
-#if (CONFIG_SND_SOC_RT5643_MODULE | CONFIG_SND_SOC_RT5643 | \
- CONFIG_SND_SOC_RT5646_MODULE | CONFIG_SND_SOC_RT5646)
+#if defined(CONFIG_SND_SOC_RT5643_MODULE) || defined(CONFIG_SND_SOC_RT5643) || \
+ defined(CONFIG_SND_SOC_RT5646_MODULE) || defined(CONFIG_SND_SOC_RT5646)
if (dai_sel & RT5640_U_IF3) {
mask_clk = RT5640_I2S_BCLK_MS3_MASK | RT5640_I2S_PD3_MASK;
val_clk = bclk_ms << RT5640_I2S_BCLK_MS3_SFT |
@@ -2006,8 +2012,8 @@ static int rt5640_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
RT5640_I2S_MS_MASK | RT5640_I2S_BP_MASK |
RT5640_I2S_DF_MASK, reg_val);
}
-#if (CONFIG_SND_SOC_RT5643_MODULE | CONFIG_SND_SOC_RT5643 | \
- CONFIG_SND_SOC_RT5646_MODULE | CONFIG_SND_SOC_RT5646)
+#if defined(CONFIG_SND_SOC_RT5643_MODULE) || defined(CONFIG_SND_SOC_RT5643) || \
+ defined(CONFIG_SND_SOC_RT5646_MODULE) || defined(CONFIG_SND_SOC_RT5646)
if (dai_sel & RT5640_U_IF3) {
snd_soc_update_bits(codec, RT5640_I2S3_SDP,
RT5640_I2S_MS_MASK | RT5640_I2S_BP_MASK |
@@ -2135,10 +2141,8 @@ static int rt5640_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
break;
case RT5640_PLL1_S_BCLK1:
case RT5640_PLL1_S_BCLK2:
-
-#if (CONFIG_SND_SOC_RT5643_MODULE | CONFIG_SND_SOC_RT5643 | \
- CONFIG_SND_SOC_RT5646_MODULE | CONFIG_SND_SOC_RT5646)
-
+#if defined(CONFIG_SND_SOC_RT5643_MODULE) || defined(CONFIG_SND_SOC_RT5643) || \
+ defined(CONFIG_SND_SOC_RT5646_MODULE) || defined(CONFIG_SND_SOC_RT5646)
case RT5640_PLL1_S_BCLK3:
#endif
@@ -2277,7 +2281,9 @@ static int rt5640_set_bias_level(struct snd_soc_codec *codec,
RT5640_PWR_FV1 | RT5640_PWR_FV2,
RT5640_PWR_FV1 | RT5640_PWR_FV2);
codec->cache_only = false;
+ codec->cache_sync = 1;
snd_soc_cache_sync(codec);
+ rt5640_index_sync(codec);
}
break;
@@ -2358,8 +2364,7 @@ static int rt5640_probe(struct snd_soc_codec *codec)
rt5640_reg_init(codec);
#endif
-
-#if (CONFIG_SND_SOC_RT5642_MODULE | CONFIG_SND_SOC_RT5642)
+#if defined(CONFIG_SND_SOC_RT5642_MODULE) || defined(CONFIG_SND_SOC_RT5642)
rt5640_register_dsp(codec);
#endif
@@ -2390,6 +2395,7 @@ static int rt5640_remove(struct snd_soc_codec *codec)
#ifdef CONFIG_PM
static int rt5640_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
+ rt5640_reset(codec);
rt5640_set_bias_level(codec, SND_SOC_BIAS_OFF);
snd_soc_write(codec, RT5640_PWR_ANLG1, 0);
@@ -2398,6 +2404,14 @@ static int rt5640_suspend(struct snd_soc_codec *codec, pm_message_t state)
static int rt5640_resume(struct snd_soc_codec *codec)
{
+ int ret = 0 ;
+
+ codec->cache_sync = 1;
+ ret = snd_soc_cache_sync(codec);
+ if (ret) {
+ dev_err(codec->dev,"Failed to sync cache: %d\n", ret);
+ return ret;
+ }
rt5640_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
@@ -2458,8 +2472,8 @@ struct snd_soc_dai_driver rt5640_dai[] = {
},
.ops = &rt5640_aif_dai_ops,
},
-#if (CONFIG_SND_SOC_RT5643_MODULE | CONFIG_SND_SOC_RT5643 | \
- CONFIG_SND_SOC_RT5646_MODULE | CONFIG_SND_SOC_RT5646)
+#if defined(CONFIG_SND_SOC_RT5643_MODULE) || defined(CONFIG_SND_SOC_RT5643) || \
+ defined(CONFIG_SND_SOC_RT5646_MODULE) || defined(CONFIG_SND_SOC_RT5646)
{
.name = "rt5640-aif3",
.id = RT5640_AIF3,
diff --git a/sound/soc/codecs/second_rate_pps_driver.h b/sound/soc/codecs/second_rate_pps_driver.h
index c6c128a027dd..9956c08bcd80 100644
--- a/sound/soc/codecs/second_rate_pps_driver.h
+++ b/sound/soc/codecs/second_rate_pps_driver.h
@@ -14,13 +14,6 @@ static control main44_VOLUME_controls[] = {
static char *main44_VOLUME_control_names[] = {
};
-
-
-static char *main44_REG_Section_names[] = {
- "miniDSP_A_reg_values",
- "miniDSP_D_reg_values",
-};
-
reg_value main44_REG_Section_init_program[] = {
{ 0,0x0},
{ 0x7F,0x00},
diff --git a/sound/soc/codecs/spdif_transciever.c b/sound/soc/codecs/spdif_transciever.c
index 16ea0ed77355..6173b3a5b082 100644
--- a/sound/soc/codecs/spdif_transciever.c
+++ b/sound/soc/codecs/spdif_transciever.c
@@ -77,7 +77,7 @@ static struct snd_soc_dai_driver dit_stub_dai = {
static int spdif_dit_probe(struct platform_device *pdev)
{
- if(machine_is_kai())
+ if(machine_is_kai() || machine_is_tegra_enterprise())
return snd_soc_register_codec(&pdev->dev,
&soc_codec_spdif_dit1, &dit_stub_dai, 1);
else
diff --git a/sound/soc/codecs/tlv320aic326x.c b/sound/soc/codecs/tlv320aic326x.c
index 8bbd295a3328..5d6b92904d56 100644
--- a/sound/soc/codecs/tlv320aic326x.c
+++ b/sound/soc/codecs/tlv320aic326x.c
@@ -81,9 +81,6 @@ static u8 aic3262_reg_ctl;
* This function reprograms the clock dividers etc. this flag can be used to
* disable this when the clock dividers are programmed by pps config file
*/
-static int soc_static_freq_config = 1;
-static struct aic3262_priv *aic3262_priv_data;
-static struct i2c_client *i2c_pdev;
static struct snd_soc_codec *aic3262_codec;
/*
@@ -849,7 +846,6 @@ static const struct aic3262_rate_divs aic3262_divs[] = {
static void aic3262_multi_i2s_dump_regs(struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
- struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
unsigned int counter;
DBG(KERN_INFO "#%s: Dai Active %d ASI%d REGS DUMP\n",
@@ -1965,7 +1961,7 @@ static int aic3262_multi_i2s_hw_params(struct snd_pcm_substream *substream,
* We can use this function to disable the DAC and ADC specific inputs from the
* individual ASI Ports of the Audio Codec.
*/
-static int aic3262_multi_i2s_shutdown(struct snd_pcm_substream *substream,
+static void aic3262_multi_i2s_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -2106,7 +2102,7 @@ static int aic3262_multi_i2s_shutdown(struct snd_pcm_substream *substream,
aic3262->active_count--;
}
err:
- return 0;
+ return;
}
@@ -2547,13 +2543,13 @@ static const struct snd_kcontrol_new hpl_output_mixer_controls[] = {
SOC_DAPM_SINGLE("MAL Switch", HP_AMP_CNTL_R1, 7, 1, 0),
SOC_DAPM_SINGLE("LDAC Switch", HP_AMP_CNTL_R1, 5, 1, 0),
SOC_DAPM_SINGLE_TLV("LOL-B1 Volume", HP_AMP_CNTL_R2, 0,
- 0x7f, 1, lo_hp_tlv),
+ 0x7f, 0, lo_hp_tlv),
};
/* Right HPR Mixer */
static const struct snd_kcontrol_new hpr_output_mixer_controls[] = {
SOC_DAPM_SINGLE_TLV("LOR-B1 Volume", HP_AMP_CNTL_R3, 0,
- 0x7f, 1, lo_hp_tlv),
+ 0x7f, 0, lo_hp_tlv),
SOC_DAPM_SINGLE("LDAC Switch", HP_AMP_CNTL_R1, 2, 1, 0),
SOC_DAPM_SINGLE("RDAC Switch", HP_AMP_CNTL_R1, 4, 1, 0),
SOC_DAPM_SINGLE("MAR Switch", HP_AMP_CNTL_R1, 6, 1, 0),
@@ -3565,7 +3561,7 @@ void aic3262_write_reg_cache(struct snd_soc_codec *codec,
*----------------------------------------------------------------------------
*/
-u8 aic3262_read(struct snd_soc_codec *codec, u16 reg)
+unsigned int aic3262_read(struct snd_soc_codec *codec, unsigned int reg)
{
struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
u8 value;
@@ -3573,7 +3569,7 @@ u8 aic3262_read(struct snd_soc_codec *codec, u16 reg)
u16 *cache = codec->reg_cache;
u16 cmd;
u8 buffer[2];
- int rc;
+ int rc = 0;
reg = reg % 128;
if (reg >= AIC3262_CACHEREGNUM) {
@@ -3619,7 +3615,8 @@ u8 aic3262_read(struct snd_soc_codec *codec, u16 reg)
*
*----------------------------------------------------------------------------
*/
-int aic3262_write(struct snd_soc_codec *codec, u16 reg, u8 value)
+int aic3262_write(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int value)
{
struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
u8 data[2];
@@ -3855,8 +3852,6 @@ int i2c_verify_book0(struct snd_soc_codec *codec)
static int aic3262_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
- struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
- u8 value;
switch (level) {
/* full On */
case SND_SOC_BIAS_ON:
@@ -4400,6 +4395,7 @@ static int aic3262_spi_write(struct spi_device *spi, const char *data, int len)
return len;
}
+#ifdef RUN_DELAYED_WORK
/*
* This function forces any delayed work to be queued and run.
*/
@@ -4418,6 +4414,8 @@ static int run_delayed_work(struct delayed_work *dwork)
}
return ret;
}
+#endif
+
static int __devinit aic3262_spi_probe(struct spi_device *spi)
{
int ret;
diff --git a/sound/soc/codecs/tlv320aic326x.h b/sound/soc/codecs/tlv320aic326x.h
index a31cc9eca5ca..bfcbefc5c079 100644
--- a/sound/soc/codecs/tlv320aic326x.h
+++ b/sound/soc/codecs/tlv320aic326x.h
@@ -36,7 +36,7 @@
/* Enable register caching on write */
#define EN_REG_CACHE 1
-#define MULTIBYTE_CONFIG_SUPPORT
+//#define MULTIBYTE_CONFIG_SUPPORT
/*Setting all codec reg/write locally*/
/* This definition is added as the snd_ direct call are
@@ -45,12 +45,12 @@ page, so fix that before commenting this line*/
#define LOCAL_REG_ACCESS 1
/* Macro to enable the inclusion of tiload kernel driver */
-#define AIC3262_TiLoad
+//#define AIC3262_TiLoad
/* Macro enables or disables support for miniDSP in the driver */
/* Enable the AIC3262_TiLoad macro first before enabling these macros */
-#define CONFIG_MINI_DSP
+//#define CONFIG_MINI_DSP
/*#undef CONFIG_MINI_DSP*/
/* Enable or disable controls to have Input routing*/
@@ -657,11 +657,12 @@ extern int aic326x_headset_detect(struct snd_soc_codec *codec,
extern int aic326x_headset_button_init(struct snd_soc_codec *codec,
struct snd_soc_jack *jack, int jack_type);
-extern u8 aic3262_read(struct snd_soc_codec *codec, u16 reg);
+extern unsigned int aic3262_read(struct snd_soc_codec *codec, unsigned int reg);
extern u16 aic3262_read_2byte(struct snd_soc_codec *codec, u16 reg);
extern int aic3262_reset_cache(struct snd_soc_codec *codec);
extern int aic3262_change_page(struct snd_soc_codec *codec, u8 new_page);
-extern int aic3262_write(struct snd_soc_codec *codec, u16 reg, u8 value);
+extern int aic3262_write(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int value);
extern void aic3262_write_reg_cache(struct snd_soc_codec *codec,
u16 reg, u8 value);
extern int aic3262_change_book(struct snd_soc_codec *codec, u8 new_book);
diff --git a/sound/soc/codecs/tlv320aic326x_mini-dsp.c b/sound/soc/codecs/tlv320aic326x_mini-dsp.c
index 6d55abb4dac8..0ef0fd09760c 100644
--- a/sound/soc/codecs/tlv320aic326x_mini-dsp.c
+++ b/sound/soc/codecs/tlv320aic326x_mini-dsp.c
@@ -601,25 +601,27 @@ struct process_flow{
int
set_minidsp_mode(struct snd_soc_codec *codec, int new_mode, int new_config)
{
-
- if (codec == NULL) {
- printk(KERN_INFO "%s codec is NULL\n",__func__);
- }
- struct aic3262_priv *aic326x = snd_soc_codec_get_drvdata(codec);
- struct snd_soc_dapm_context *dapm = &codec->dapm;
+ struct aic3262_priv *aic326x;
+ struct snd_soc_dapm_context *dapm;
struct process_flow * pflows = &miniDSP_programs[new_mode];
- u8 reg63, reg81, pll_pow, ndac_pow, mdac_pow, nadc_pow, madc_pow;
-
+ u8 pll_pow, ndac_pow, mdac_pow, nadc_pow;
u8 adc_status,dac_status;
- u8 reg, val;
- u8 shift;
- volatile u16 counter;
- int (*ptransfer)(struct snd_soc_codec *codec,
- reg_value *program_ptr,
- int size);
+ int (*ptransfer)(struct snd_soc_codec *codec, reg_value *program_ptr,
+ int size);
printk("%s:New Switch mode = %d New Config= %d\n", __func__, new_mode,new_config);
+
+ if (codec == NULL) {
+ printk(KERN_INFO "%s codec is NULL\n", __func__);
+ return 0;
+ }
+ aic326x = snd_soc_codec_get_drvdata(codec);
+ dapm = &codec->dapm;
+
+ printk(KERN_INFO "%s:New Switch mode = %d New Config= %d\n", __func__,
+ new_mode, new_config);
+
if (new_mode >= ARRAY_SIZE(miniDSP_programs))
return 0; // error condition
if (new_config > MAXCONFIG)
@@ -1231,7 +1233,7 @@ static int __new_control_put_minidsp_mux(struct snd_kcontrol *kcontrol,
int ret_val = -1, array_size;
control *array;
char **array_names;
- char *control_name, *control_name1, *control_name2;
+ char *control_name, *control_name1;
struct aic3262_priv *aic326x = snd_soc_codec_get_drvdata(codec);
i2c = codec->control_data;
diff --git a/sound/soc/codecs/tlv320aic326x_minidsp_config.c b/sound/soc/codecs/tlv320aic326x_minidsp_config.c
index e34ffbe2ca82..97a41c3ecf2b 100644
--- a/sound/soc/codecs/tlv320aic326x_minidsp_config.c
+++ b/sound/soc/codecs/tlv320aic326x_minidsp_config.c
@@ -347,17 +347,12 @@ int aic3262_add_multiconfig_controls(struct snd_soc_codec *codec)
*---------------------------------------------------------------------------
*/
void minidsp_multiconfig(struct snd_soc_codec *codec,
- reg_value *a_patch, int a_size,
- reg_value *d_patch, int d_size)
+ reg_value *a_patch, int a_size, reg_value *d_patch, int d_size)
{
- struct aic3262_priv *aic326x = snd_soc_codec_get_drvdata(codec);
- int val1,val2;
int adc_status,dac_status;
int (*ptransfer)(struct snd_soc_codec *codec,
- reg_value *program_ptr,
- int size);
-
-printk("======in the config_multiconfiguration function==== \n");
+ reg_value *program_ptr, int size);
+ printk(KERN_INFO "======in the config_multiconfiguration function====\n");
#ifndef MULTIBYTE_I2C
ptransfer = byte_i2c_array_transfer;
#else
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index df4d0ee6f975..2a2d16886989 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -1404,6 +1404,7 @@ static struct {
{ 1500, 0x9, 0x2, 2 },
};
+#ifdef SYS_BCLK_RATIO
/* CLK_SYS/BCLK ratios - multiplied by 10 due to .5s */
static struct {
int ratio;
@@ -1427,6 +1428,7 @@ static struct {
{ 440, 19 },
{ 480, 20 },
};
+#endif
/* Sample rates for DSP */
static struct {
diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/sh/siu_pcm.c
index de9abd032fd4..5cfcc655e95f 100644
--- a/sound/soc/sh/siu_pcm.c
+++ b/sound/soc/sh/siu_pcm.c
@@ -180,13 +180,8 @@ static int siu_pcm_rd_set(struct siu_port *port_info,
sg_dma_len(&sg) = size;
sg_dma_address(&sg) = buff;
-<<<<<<< HEAD
- desc = siu_stream->chan->device->device_prep_slave_sg(siu_stream->chan,
- &sg, 1, DMA_FROM_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-=======
desc = dmaengine_prep_slave_sg(siu_stream->chan,
&sg, 1, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
->>>>>>> 1605282... dmaengine/dma_slave: introduce inline wrappers
if (!desc) {
dev_err(dev, "Failed to allocate dma descriptor\n");
return -ENOMEM;
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index 274421b483de..079a28ccbe99 100644
--- a/sound/soc/tegra/Makefile
+++ b/sound/soc/tegra/Makefile
@@ -1,5 +1,7 @@
GCOV_PROFILE := y
+subdir-ccflags-y := -Werror
+
# Tegra platform Support
snd-soc-tegra-pcm-objs := tegra_pcm.o
snd-soc-tegra-tdm-pcm-objs := tegra_tdm_pcm.o
diff --git a/sound/soc/tegra/tegra20_das.c b/sound/soc/tegra/tegra20_das.c
index 0774d360399a..29c4582cfa79 100644
--- a/sound/soc/tegra/tegra20_das.c
+++ b/sound/soc/tegra/tegra20_das.c
@@ -50,7 +50,7 @@ static inline u32 tegra20_das_read(u32 reg)
}
#ifdef CONFIG_PM
-int tegra20_das_resume()
+int tegra20_das_resume(void)
{
int i, reg;
@@ -67,7 +67,7 @@ int tegra20_das_resume()
}
#endif
-int tegra20_das_set_tristate(int dap_id, int is_tristate)
+void tegra20_das_set_tristate(int dap_id, int is_tristate)
{
enum tegra_pingroup pin;
enum tegra_tristate tristate;
@@ -86,7 +86,7 @@ int tegra20_das_set_tristate(int dap_id, int is_tristate)
pin = TEGRA_PINGROUP_DAP4;
break;
default:
- return -EINVAL;
+ return;
}
if (is_tristate)
diff --git a/sound/soc/tegra/tegra20_das.h b/sound/soc/tegra/tegra20_das.h
index 0d58c7d1bc3f..5cd2d07d43b8 100644
--- a/sound/soc/tegra/tegra20_das.h
+++ b/sound/soc/tegra/tegra20_das.h
@@ -98,7 +98,7 @@ struct tegra20_das {
#ifdef CONFIG_PM
/* Restores the das registers from cache */
-extern int tegra20_das_resume();
+extern int tegra20_das_resume(void);
#endif
/*
* Terminology:
@@ -143,6 +143,6 @@ extern int tegra20_das_connect_dap_to_dap(int dap_id, int other_dap_sel,
*/
extern int tegra20_das_connect_dac_to_dap(int dac_id, int dap_sel);
-extern int tegra20_das_set_tristate(int dap_id, int is_tristate);
+extern void tegra20_das_set_tristate(int dap_id, int is_tristate);
#endif
diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c
index ea772f40464b..6fac8fc0177b 100644
--- a/sound/soc/tegra/tegra30_ahub.c
+++ b/sound/soc/tegra/tegra30_ahub.c
@@ -3,6 +3,7 @@
*
* Author: Stephen Warren <swarren@nvidia.com>
* Copyright (C) 2011 - NVIDIA, Inc.
+ * 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
@@ -281,66 +282,61 @@ int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif,
return 0;
}
-int tegra30_ahub_rx_fifo_is_busy(enum tegra30_ahub_rxcif rxcif)
+int tegra30_ahub_rx_fifo_is_enabled(int i2s_id)
{
- int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
- int reg, val;
-
- reg = TEGRA30_AHUB_CHANNEL_STATUS +
- (channel * TEGRA30_AHUB_CHANNEL_STATUS_STRIDE);
-
- val = tegra30_apbif_read(reg);
- val &= TEGRA30_AHUB_CHANNEL_STATUS_RX_TRIG;
+ int val, mask;
+ val = tegra30_apbif_read(TEGRA30_AHUB_I2S_LIVE_STATUS);
+ mask = (TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_RX_FIFO_ENABLED << (i2s_id*2));
+ val &= mask;
return val;
}
-int tegra30_ahub_tx_fifo_is_busy(enum tegra30_ahub_txcif txcif)
+int tegra30_ahub_tx_fifo_is_enabled(int i2s_id)
{
- int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0;
- int reg, val;
+ int val, mask;
- reg = TEGRA30_AHUB_CHANNEL_STATUS +
- (channel * TEGRA30_AHUB_CHANNEL_STATUS_STRIDE);
-
- val = tegra30_apbif_read(reg);
- val &= TEGRA30_AHUB_CHANNEL_STATUS_TX_TRIG;
+ val = tegra30_apbif_read(TEGRA30_AHUB_I2S_LIVE_STATUS);
+ mask = (TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_TX_FIFO_ENABLED << (i2s_id*2));
+ val &= mask;
return val;
}
-int tegra30_ahub_rx_fifo_clear(enum tegra30_ahub_rxcif rxcif)
+int tegra30_ahub_dam_ch0_is_enabled(int dam_id)
{
- int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
- int reg, val;
-
- reg = TEGRA30_AHUB_CHANNEL_CLEAR +
- (channel * TEGRA30_AHUB_CHANNEL_CLEAR_STRIDE);
-
- val = tegra30_apbif_read(reg);
- val |= TEGRA30_AHUB_CHANNEL_CLEAR_RX_SOFT_RESET;
- tegra30_apbif_write(reg, val);
+ int val, mask;
- tegra30_ahub_disable_clocks();
+ val = tegra30_apbif_read((TEGRA30_AHUB_DAM_LIVE_STATUS) +
+ (dam_id * TEGRA30_AHUB_DAM_LIVE_STATUS_STRIDE));
+ mask = TEGRA30_AHUB_DAM_LIVE_STATUS_RX0_ENABLED;
+ val &= mask;
- return 0;
+ return val;
}
-int tegra30_ahub_tx_fifo_clear(enum tegra30_ahub_txcif txcif)
+int tegra30_ahub_dam_ch1_is_enabled(int dam_id)
{
- int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0;
- int reg, val;
+ int val, mask;
- reg = TEGRA30_AHUB_CHANNEL_CLEAR +
- (channel * TEGRA30_AHUB_CHANNEL_CLEAR_STRIDE);
+ val = tegra30_apbif_read((TEGRA30_AHUB_DAM_LIVE_STATUS) +
+ (dam_id * TEGRA30_AHUB_DAM_LIVE_STATUS_STRIDE));
+ mask = TEGRA30_AHUB_DAM_LIVE_STATUS_RX1_ENABLED;
+ val &= mask;
- val = tegra30_apbif_read(reg);
- val |= TEGRA30_AHUB_CHANNEL_CLEAR_TX_SOFT_RESET;
- tegra30_apbif_write(reg, val);
+ return val;
+}
- tegra30_ahub_disable_clocks();
+int tegra30_ahub_dam_tx_is_enabled(int dam_id)
+{
+ int val, mask;
- return 0;
+ val = tegra30_apbif_read((TEGRA30_AHUB_DAM_LIVE_STATUS) +
+ (dam_id * TEGRA30_AHUB_DAM_LIVE_STATUS_STRIDE));
+ mask = TEGRA30_AHUB_DAM_LIVE_STATUS_TX_ENABLED;
+ val &= mask;
+
+ return val;
}
int tegra30_ahub_set_rx_fifo_pack_mode(enum tegra30_ahub_rxcif rxcif,
@@ -418,6 +414,8 @@ int tegra30_ahub_disable_rx_fifo(enum tegra30_ahub_rxcif rxcif)
val &= ~TEGRA30_AHUB_CHANNEL_CTRL_RX_EN;
tegra30_apbif_write(reg, val);
+ tegra30_ahub_disable_clocks();
+
return 0;
}
@@ -503,6 +501,8 @@ int tegra30_ahub_disable_tx_fifo(enum tegra30_ahub_txcif txcif)
val &= ~TEGRA30_AHUB_CHANNEL_CTRL_TX_EN;
tegra30_apbif_write(reg, val);
+ tegra30_ahub_disable_clocks();
+
return 0;
}
diff --git a/sound/soc/tegra/tegra30_ahub.h b/sound/soc/tegra/tegra30_ahub.h
index 2c0f5aab4db1..b5fd2363f080 100644
--- a/sound/soc/tegra/tegra30_ahub.h
+++ b/sound/soc/tegra/tegra30_ahub.h
@@ -3,6 +3,7 @@
*
* Author: Stephen Warren <swarren@nvidia.com>
* Copyright (C) 2011 - NVIDIA, Inc.
+ * 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
@@ -500,10 +501,11 @@ extern int tegra30_ahub_set_rx_cif_source(enum tegra30_ahub_rxcif rxcif,
enum tegra30_ahub_txcif txcif);
extern int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif);
-extern int tegra30_ahub_rx_fifo_is_busy(enum tegra30_ahub_rxcif rxcif);
-extern int tegra30_ahub_tx_fifo_is_busy(enum tegra30_ahub_txcif txcif);
-extern int tegra30_ahub_rx_fifo_clear(enum tegra30_ahub_rxcif rxcif);
-extern int tegra30_ahub_tx_fifo_clear(enum tegra30_ahub_txcif txcif);
+extern int tegra30_ahub_rx_fifo_is_enabled(int i2s_id);
+extern int tegra30_ahub_tx_fifo_is_enabled(int i2s_id);
+extern int tegra30_ahub_dam_ch0_is_enabled(int dam_id);
+extern int tegra30_ahub_dam_ch1_is_enabled(int dam_id);
+extern int tegra30_ahub_dam_tx_is_enabled(int dam_id);
#ifdef CONFIG_PM
extern int tegra30_ahub_apbif_resume(void);
diff --git a/sound/soc/tegra/tegra30_dam.c b/sound/soc/tegra/tegra30_dam.c
index d308179110c9..8460266d0d66 100644
--- a/sound/soc/tegra/tegra30_dam.c
+++ b/sound/soc/tegra/tegra30_dam.c
@@ -3,6 +3,7 @@
*
* Author: Nikesh Oswal <noswal@nvidia.com>
* Copyright (C) 2011 - NVIDIA, Inc.
+ * 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
@@ -27,6 +28,7 @@
#include <linux/platform_device.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
+#include <linux/delay.h>
#include <linux/io.h>
#include <sound/soc.h>
#include "tegra30_dam.h"
@@ -455,6 +457,8 @@ int tegra30_dam_set_acif(int ifc, int chid, unsigned int audio_channels,
void tegra30_dam_enable(int ifc, int on, int chid)
{
u32 old_val, val, enreg;
+ u32 old_val_dam, val_dam;
+ int dcnt = 10;
struct tegra30_dam_context *dam = dams_cont_info[ifc];
if (ifc >= TEGRA30_NR_DAM_IFC)
@@ -476,19 +480,46 @@ void tegra30_dam_enable(int ifc, int on, int chid)
val &= ~TEGRA30_DAM_CH0_CTRL_EN;
}
- if (val != old_val)
- tegra30_dam_writel(dam, val, enreg);
-
- old_val = val = tegra30_dam_readl(dam, TEGRA30_DAM_CTRL);
+ old_val_dam = val_dam = tegra30_dam_readl(dam, TEGRA30_DAM_CTRL);
if (dam->ch_enable_refcnt[dam_ch_in0] ||
dam->ch_enable_refcnt[dam_ch_in1])
- val |= TEGRA30_DAM_CTRL_DAM_EN;
+ val_dam |= TEGRA30_DAM_CTRL_DAM_EN;
else
- val &= ~TEGRA30_DAM_CTRL_DAM_EN;
+ val_dam &= ~TEGRA30_DAM_CTRL_DAM_EN;
+
+ if (val != old_val) {
+ tegra30_dam_writel(dam, val, enreg);
+
+ if (!on) {
+ if (chid == dam_ch_in0) {
+ while (tegra30_ahub_dam_ch0_is_enabled(ifc)
+ && dcnt--)
+ udelay(100);
+
+ dcnt = 10;
+ }
+ else {
+ while (tegra30_ahub_dam_ch1_is_enabled(ifc)
+ && dcnt--)
+ udelay(100);
+
+ dcnt = 10;
+ }
+ }
+ }
+
+ if (old_val_dam != val_dam) {
+ tegra30_dam_writel(dam, val_dam, TEGRA30_DAM_CTRL);
+
+ if (!on) {
+ while (tegra30_ahub_dam_tx_is_enabled(ifc) && dcnt--)
+ udelay(100);
- if (old_val != val)
- tegra30_dam_writel(dam, val, TEGRA30_DAM_CTRL);
+ dcnt = 10;
+ }
+
+ }
}
void tegra30_dam_ch0_set_datasync(struct tegra30_dam_context *dam, int datasync)
diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c
index c2750bfbef64..72e64470008a 100644
--- a/sound/soc/tegra/tegra30_i2s.c
+++ b/sound/soc/tegra/tegra30_i2s.c
@@ -7,6 +7,7 @@
* Based on code copyright/by:
*
* Copyright (c) 2009-2010, NVIDIA Corporation.
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
* Scott Peterson <speterson@nvidia.com>
*
* Copyright (C) 2010 Google, Inc.
@@ -346,6 +347,7 @@ static int tegra30_i2s_tdm_setup_clocks(struct device *dev,
dev_err(dev, "Can't set parent of I2S clock\n");
return ret;
}
+
ret = clk_set_rate(i2s->clk_i2s, *i2sclock);
if (ret) {
dev_err(dev, "Can't set I2S clock rate: %d\n", ret);
@@ -359,6 +361,13 @@ static int tegra30_i2s_tdm_setup_clocks(struct device *dev,
return ret;
}
+ ret = clk_set_parent(clk_get_parent(i2s->clk_audio_2x),
+ i2s->clk_i2s_sync);
+ if (ret) {
+ dev_err(dev, "Can't set parent of audio2x clock\n");
+ return ret;
+ }
+
ret = clk_set_rate(i2s->clk_audio_2x, *i2sclock);
if (ret) {
dev_err(dev, "Can't set audio2x clock rate\n");
@@ -367,7 +376,7 @@ static int tegra30_i2s_tdm_setup_clocks(struct device *dev,
ret = clk_set_parent(i2s->clk_i2s, i2s->clk_audio_2x);
if (ret) {
- dev_err(dev, "Can't set parent of audio2x clock\n");
+ dev_err(dev, "Can't set parent of i2s clock\n");
return ret;
}
}
@@ -382,7 +391,8 @@ static int tegra30_i2s_tdm_hw_params(struct snd_pcm_substream *substream,
struct device *dev = substream->pcm->card->dev;
struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
u32 val;
- int i2s_client_ch, i2s_audio_ch, i2s_audio_bits, i2s_client_bits;
+ int i2s_client_ch, i2s_audio_ch;
+ int i2s_audio_bits = 0, i2s_client_bits = 0;
int i2sclock, srate;
int ret;
@@ -418,6 +428,10 @@ static int tegra30_i2s_tdm_hw_params(struct snd_pcm_substream *substream,
i2s_client_bits = TEGRA30_AUDIOCIF_BITS_32;
i2s->reg_ctrl |= TEGRA30_I2S_CTRL_BIT_SIZE_32;
break;
+ default:
+ dev_err(dev, "unknown slot_width %d\n",
+ i2s->dsp_config.slot_width);
+ return -EINVAL;
}
val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) |
@@ -625,9 +639,8 @@ static void tegra30_i2s_stop_playback(struct tegra30_i2s *i2s)
i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_TX;
tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl);
}
- while (tegra30_ahub_tx_fifo_is_busy(i2s->txcif) && dcnt--)
+ while (tegra30_ahub_tx_fifo_is_enabled(i2s->id) && dcnt--)
udelay(100);
- tegra30_ahub_tx_fifo_clear(i2s->txcif);
}
static void tegra30_i2s_start_capture(struct tegra30_i2s *i2s)
@@ -647,9 +660,8 @@ static void tegra30_i2s_stop_capture(struct tegra30_i2s *i2s)
i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_RX;
tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl);
}
- while (tegra30_ahub_rx_fifo_is_busy(i2s->rxcif) && dcnt--)
+ while (tegra30_ahub_rx_fifo_is_enabled(i2s->id) && dcnt--)
udelay(100);
- tegra30_ahub_rx_fifo_clear(i2s->rxcif);
}
static int tegra30_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
@@ -800,7 +812,47 @@ static int configure_baseband_i2s(struct tegra30_i2s *i2s, int is_i2smaster,
int is_formatdsp, int channels, int rate, int bitsize)
{
u32 val;
- int i2sclock, bitcnt;
+ int i2sclock, bitcnt, ret;
+
+ i2sclock = rate * channels * bitsize * 2;
+
+ /* additional 8 for baseband */
+ if (is_formatdsp)
+ i2sclock *= 8;
+
+ if (is_i2smaster) {
+ ret = clk_set_parent(i2s->clk_i2s, i2s->clk_pll_a_out0);
+ if (ret) {
+ pr_err("Can't set parent of I2S clock\n");
+ return ret;
+ }
+
+ ret = clk_set_rate(i2s->clk_i2s, i2sclock);
+ if (ret) {
+ pr_err("Can't set I2S clock rate: %d\n", ret);
+ return ret;
+ }
+ } else {
+ ret = clk_set_rate(i2s->clk_i2s_sync, i2sclock);
+ if (ret) {
+ pr_err("Can't set I2S sync clock rate\n");
+ return ret;
+ }
+
+ ret = clk_set_rate(i2s->clk_audio_2x, i2sclock);
+ if (ret) {
+ pr_err("Can't set I2S sync clock rate\n");
+ return ret;
+ }
+
+ ret = clk_set_parent(i2s->clk_i2s, i2s->clk_audio_2x);
+ if (ret) {
+ pr_err("Can't set parent of audio2x clock\n");
+ return ret;
+ }
+ }
+
+ tegra30_i2s_enable_clocks(i2s);
i2s->reg_ctrl &= ~(TEGRA30_I2S_CTRL_FRAME_FORMAT_MASK |
TEGRA30_I2S_CTRL_LRCK_MASK |
@@ -835,14 +887,6 @@ static int configure_baseband_i2s(struct tegra30_i2s *i2s, int is_i2smaster,
(1 << TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_SHIFT);
tegra30_i2s_write(i2s, TEGRA30_I2S_OFFSET, val);
- i2sclock = rate * channels * bitsize * 2;
-
- /* additional 8 for baseband */
- if (is_formatdsp)
- i2sclock *= 8;
-
- clk_set_rate(i2s->clk_i2s, i2sclock);
-
if (is_formatdsp) {
bitcnt = (i2sclock/rate) - 1;
val = bitcnt << TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT;
@@ -905,8 +949,6 @@ int tegra30_make_voice_call_connections(struct codec_config *codec_info,
codec_i2s = &i2scont[codec_info->i2s_id];
bb_i2s = &i2scont[bb_info->i2s_id];
- tegra30_i2s_enable_clocks(codec_i2s);
- tegra30_i2s_enable_clocks(bb_i2s);
/* increment the codec i2s playback ref count */
codec_i2s->playback_ref_count++;
@@ -957,10 +999,7 @@ int tegra30_make_voice_call_connections(struct codec_config *codec_info,
tegra30_dam_enable(bb_i2s->dam_ifc, TEGRA30_DAM_ENABLE,
TEGRA30_DAM_CHIN0_SRC);
- /* if this is the only user of i2s tx then enable it*/
- if (codec_i2s->playback_ref_count == 1)
- codec_i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_TX;
-
+ codec_i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_TX;
codec_i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_RX;
tegra30_i2s_write(codec_i2s, TEGRA30_I2S_CTRL,
codec_i2s->reg_ctrl);
@@ -977,61 +1016,89 @@ int tegra30_break_voice_call_connections(struct codec_config *codec_info,
{
struct tegra30_i2s *codec_i2s;
struct tegra30_i2s *bb_i2s;
+ int dcnt = 10;
codec_i2s = &i2scont[codec_info->i2s_id];
bb_i2s = &i2scont[bb_info->i2s_id];
- /* disconnect the ahub connections */
-
- /* if this is the only user of i2s tx then break ahub
- i2s rx connection */
- if (codec_i2s->playback_ref_count == 1)
- tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_I2S0_RX0
- + codec_info->i2s_id);
+ /*Disable Codec I2S RX (TX to ahub)*/
+ codec_i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_RX;
+ tegra30_i2s_write(codec_i2s, TEGRA30_I2S_CTRL, codec_i2s->reg_ctrl);
- tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_I2S0_RX0
- + bb_info->i2s_id);
- tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_DAM0_RX0
- + (codec_i2s->dam_ifc*2));
- tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_DAM0_RX0
- + (bb_i2s->dam_ifc*2));
+ while (tegra30_ahub_rx_fifo_is_enabled(codec_i2s->id) && dcnt--)
+ udelay(100);
- /* disable the i2s */
+ dcnt = 10;
- /* if this is the only user of i2s tx then disable it*/
- if (codec_i2s->playback_ref_count == 1)
- codec_i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_TX;
+ /*Disable baseband DAM*/
+ tegra30_dam_enable(bb_i2s->dam_ifc, TEGRA30_DAM_DISABLE,
+ TEGRA30_DAM_CHIN0_SRC);
+ tegra30_dam_free_channel(bb_i2s->dam_ifc, TEGRA30_DAM_CHIN0_SRC);
+ bb_i2s->dam_ch_refcount--;
+ if (!bb_i2s->dam_ch_refcount)
+ tegra30_dam_free_controller(bb_i2s->dam_ifc);
- codec_i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_RX;
- tegra30_i2s_write(codec_i2s, TEGRA30_I2S_CTRL, codec_i2s->reg_ctrl);
+ /*Disable baseband I2S TX (RX from ahub)*/
bb_i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_TX;
+ tegra30_i2s_write(bb_i2s, TEGRA30_I2S_CTRL, bb_i2s->reg_ctrl);
+
+ while (tegra30_ahub_tx_fifo_is_enabled(bb_i2s->id) && dcnt--)
+ udelay(100);
+
+ dcnt = 10;
+
+ /*Disable baseband I2S RX (TX to ahub)*/
bb_i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_RX;
tegra30_i2s_write(bb_i2s, TEGRA30_I2S_CTRL, bb_i2s->reg_ctrl);
- tegra30_i2s_disable_clocks(codec_i2s);
- tegra30_i2s_disable_clocks(bb_i2s);
- /* decrement the codec i2s playback ref count */
- codec_i2s->playback_ref_count--;
- bb_i2s->playback_ref_count--;
+ while (tegra30_ahub_rx_fifo_is_enabled(bb_i2s->id) && dcnt--)
+ udelay(100);
+
+ dcnt = 10;
- /* disable the codec dam */
+ /*Disable Codec DAM*/
tegra30_dam_enable(codec_i2s->dam_ifc,
TEGRA30_DAM_DISABLE, TEGRA30_DAM_CHIN0_SRC);
- tegra30_dam_disable_clock(codec_i2s->dam_ifc);
tegra30_dam_free_channel(codec_i2s->dam_ifc,
TEGRA30_DAM_CHIN0_SRC);
codec_i2s->dam_ch_refcount--;
if (!codec_i2s->dam_ch_refcount)
tegra30_dam_free_controller(codec_i2s->dam_ifc);
- /* disable the bb dam */
- tegra30_dam_enable(bb_i2s->dam_ifc, TEGRA30_DAM_DISABLE,
- TEGRA30_DAM_CHIN0_SRC);
+ /*Disable Codec I2S TX (RX from ahub)*/
+ if (codec_i2s->playback_ref_count == 1)
+ codec_i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_TX;
+
+ tegra30_i2s_write(codec_i2s, TEGRA30_I2S_CTRL, codec_i2s->reg_ctrl);
+
+ while (tegra30_ahub_tx_fifo_is_enabled(codec_i2s->id) && dcnt--)
+ udelay(100);
+
+ dcnt = 10;
+
+ /* Disconnect the ahub connections */
+ /* If this is the only user of i2s tx then break ahub
+ i2s rx connection */
+ if (codec_i2s->playback_ref_count == 1)
+ tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_I2S0_RX0
+ + codec_info->i2s_id);
+
+ tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_I2S0_RX0
+ + bb_info->i2s_id);
+ tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_DAM0_RX0
+ + (codec_i2s->dam_ifc*2));
+ tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_DAM0_RX0
+ + (bb_i2s->dam_ifc*2));
+
+ /* Decrement the codec and bb i2s playback ref count */
+ codec_i2s->playback_ref_count--;
+ bb_i2s->playback_ref_count--;
+
+ /* Disable the clocks */
+ tegra30_i2s_disable_clocks(codec_i2s);
+ tegra30_i2s_disable_clocks(bb_i2s);
+ tegra30_dam_disable_clock(codec_i2s->dam_ifc);
tegra30_dam_disable_clock(bb_i2s->dam_ifc);
- tegra30_dam_free_channel(bb_i2s->dam_ifc, TEGRA30_DAM_CHIN0_SRC);
- bb_i2s->dam_ch_refcount--;
- if (!bb_i2s->dam_ch_refcount)
- tegra30_dam_free_controller(bb_i2s->dam_ifc);
return 0;
}
diff --git a/sound/soc/tegra/tegra_aic326x.c b/sound/soc/tegra/tegra_aic326x.c
index a5c6fc0aecb7..4cacb6758eb8 100644
--- a/sound/soc/tegra/tegra_aic326x.c
+++ b/sound/soc/tegra/tegra_aic326x.c
@@ -1062,6 +1062,10 @@ static int tegra_aic326x_init(struct snd_soc_pcm_runtime *rtd)
if (ret < 0)
return ret;
+ ret = tegra_asoc_utils_register_ctls(&machine->util_data);
+ if (ret < 0)
+ return ret;
+
snd_soc_dapm_force_enable_pin(dapm, "MICBIAS_EXT ON");
snd_soc_dapm_force_enable_pin(dapm,"MICBIAS_INT ON");
snd_soc_dapm_sync(dapm);
diff --git a/sound/soc/tegra/tegra_asoc_utils.c b/sound/soc/tegra/tegra_asoc_utils.c
index b134f0808afa..6ab5b2d46a1f 100644
--- a/sound/soc/tegra/tegra_asoc_utils.c
+++ b/sound/soc/tegra/tegra_asoc_utils.c
@@ -27,11 +27,14 @@
#include <mach/clk.h>
+#include <sound/soc.h>
+
+#include "tegra_pcm.h"
#include "tegra_asoc_utils.h"
int g_is_call_mode;
-bool tegra_is_voice_call_active()
+bool tegra_is_voice_call_active(void)
{
if (g_is_call_mode)
return true;
@@ -40,6 +43,115 @@ bool tegra_is_voice_call_active()
}
EXPORT_SYMBOL_GPL(tegra_is_voice_call_active);
+static int tegra_get_avp_device(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tegra_asoc_utils_data *data = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] = data->avp_device_id;
+ return 0;
+}
+
+static int tegra_set_avp_device(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tegra_asoc_utils_data *data = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_card *card = data->card;
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_pcm_substream *substream;
+ struct tegra_runtime_data *prtd;
+ int id, old_id = data->avp_device_id;
+
+ id = ucontrol->value.integer.value[0];
+ if ((id >= card->num_rtd) || (id < 0))
+ id = -1;
+
+ if (old_id >= 0) {
+ rtd = &card->rtd[old_id];
+ substream =
+ rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+ if (substream && substream->runtime) {
+ prtd = substream->runtime->private_data;
+ if (prtd->running)
+ return -EBUSY;
+ if (prtd)
+ prtd->disable_intr = false;
+ }
+ }
+
+ if (id >= 0) {
+ rtd = &card->rtd[id];
+ substream =
+ rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+ if (substream && substream->runtime) {
+ prtd = substream->runtime->private_data;
+ if (prtd->running)
+ return -EBUSY;
+ if (prtd)
+ prtd->disable_intr = true;
+ }
+ }
+ data->avp_device_id = id;
+ return 1;
+}
+
+static int tegra_get_dma_ch_id(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tegra_asoc_utils_data *data = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_card *card = data->card;
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_pcm_substream *substream;
+ struct tegra_runtime_data *prtd;
+
+ ucontrol->value.integer.value[0] = -1;
+ if (data->avp_device_id < 0)
+ return 0;
+
+ rtd = &card->rtd[data->avp_device_id];
+ substream = rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+ if (!substream || !substream->runtime)
+ return 0;
+
+ prtd = substream->runtime->private_data;
+ if (!prtd || !prtd->dma_chan)
+ return 0;
+
+ ucontrol->value.integer.value[0] =
+ tegra_dma_get_channel_id(prtd->dma_chan);
+ return 0;
+}
+
+static int tegra_get_dma_addr(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tegra_asoc_utils_data *data = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_card *card = data->card;
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_pcm_substream *substream;
+
+ ucontrol->value.integer.value[0] = 0;
+ if (data->avp_device_id < 0)
+ return 0;
+
+ rtd = &card->rtd[data->avp_device_id];
+ substream = rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+ if (!substream || !substream->runtime)
+ return 0;
+
+ ucontrol->value.integer.value[0] = substream->runtime->dma_addr;
+ return 0;
+}
+
+struct snd_kcontrol_new tegra_avp_controls[] = {
+ SOC_SINGLE_EXT("AVP alsa device select", 0, 0, TEGRA_ALSA_MAX_DEVICES, \
+ 0, tegra_get_avp_device, tegra_set_avp_device),
+ SOC_SINGLE_EXT("AVP DMA channel id", 0, 0, TEGRA_DMA_MAX_CHANNELS, \
+ 0, tegra_get_dma_ch_id, NULL),
+ SOC_SINGLE_EXT("AVP DMA address", 0, 0, 0xFFFFFFFF, \
+ 0, tegra_get_dma_addr, NULL),
+};
+
int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate,
int mclk)
{
@@ -152,6 +264,26 @@ int tegra_asoc_utils_clk_disable(struct tegra_asoc_utils_data *data)
}
EXPORT_SYMBOL_GPL(tegra_asoc_utils_clk_disable);
+int tegra_asoc_utils_register_ctls(struct tegra_asoc_utils_data *data)
+{
+ int i;
+ int ret = 0;
+
+ /* Add AVP related alsa controls */
+ data->avp_device_id = -1;
+ for (i = 0; i < ARRAY_SIZE(tegra_avp_controls); i++) {
+ ret = snd_ctl_add(data->card->snd_card,
+ snd_ctl_new1(&tegra_avp_controls[i], data));
+ if (ret < 0) {
+ dev_err(data->dev, "Can't add avp alsa controls");
+ return ret;
+ }
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(tegra_asoc_utils_register_ctls);
+
int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
struct device *dev, struct snd_soc_card *card)
{
@@ -276,6 +408,10 @@ void tegra_asoc_utils_fini(struct tegra_asoc_utils_data *data)
clk_put(data->clk_out1);
clk_put(data->clk_cdev1);
+ /* Just to make sure that clk_cdev1 should turn off in case if it is
+ * switched on by some codec whose hw switch is not registered.*/
+ if (tegra_is_clk_enabled(data->clk_cdev1))
+ clk_disable(data->clk_cdev1);
if (!IS_ERR(data->clk_pll_a_out0))
clk_put(data->clk_pll_a_out0);
diff --git a/sound/soc/tegra/tegra_asoc_utils.h b/sound/soc/tegra/tegra_asoc_utils.h
index 512df0d54eb1..0423f02b76cc 100644
--- a/sound/soc/tegra/tegra_asoc_utils.h
+++ b/sound/soc/tegra/tegra_asoc_utils.h
@@ -25,6 +25,8 @@
#define TEGRA30_I2S_MASTER_PLAYBACK 1
+#define TEGRA_ALSA_MAX_DEVICES 6
+#define TEGRA_DMA_MAX_CHANNELS 32
struct clk;
struct device;
@@ -41,6 +43,7 @@ struct tegra_asoc_utils_data {
int set_baseclock;
int set_mclk;
int lock_count;
+ int avp_device_id;
};
int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate,
@@ -52,6 +55,7 @@ int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
void tegra_asoc_utils_fini(struct tegra_asoc_utils_data *data);
int tegra_asoc_utils_clk_enable(struct tegra_asoc_utils_data *data);
int tegra_asoc_utils_clk_disable(struct tegra_asoc_utils_data *data);
+int tegra_asoc_utils_register_ctls(struct tegra_asoc_utils_data *data);
#endif
diff --git a/sound/soc/tegra/tegra_max98088.c b/sound/soc/tegra/tegra_max98088.c
index 63a067338dc4..82c2b930a39e 100644
--- a/sound/soc/tegra/tegra_max98088.c
+++ b/sound/soc/tegra/tegra_max98088.c
@@ -96,6 +96,7 @@ struct tegra_max98088 {
#endif
enum snd_soc_bias_level bias_level;
struct snd_soc_card *pcard;
+ volatile int clock_enabled;
};
static int tegra_call_mode_info(struct snd_kcontrol *kcontrol,
@@ -926,6 +927,7 @@ static int tegra_max98088_init(struct snd_soc_pcm_runtime *rtd)
machine->pcard = card;
machine->bias_level = SND_SOC_BIAS_STANDBY;
+ machine->clock_enabled = 1;
if (gpio_is_valid(pdata->gpio_spkr_en)) {
ret = gpio_request(pdata->gpio_spkr_en, "spkr_en");
@@ -1007,6 +1009,10 @@ static int tegra_max98088_init(struct snd_soc_pcm_runtime *rtd)
if (ret < 0)
return ret;
+ ret = tegra_asoc_utils_register_ctls(&machine->util_data);
+ if (ret < 0)
+ return ret;
+
snd_soc_dapm_nc_pin(dapm, "INA1");
snd_soc_dapm_nc_pin(dapm, "INA2");
snd_soc_dapm_nc_pin(dapm, "INB1");
@@ -1070,8 +1076,11 @@ static int tegra30_soc_set_bias_level(struct snd_soc_card *card,
struct tegra_max98088 *machine = snd_soc_card_get_drvdata(card);
if (machine->bias_level == SND_SOC_BIAS_OFF &&
- level != SND_SOC_BIAS_OFF)
+ level != SND_SOC_BIAS_OFF && (!machine->clock_enabled)) {
+ machine->clock_enabled = 1;
tegra_asoc_utils_clk_enable(&machine->util_data);
+ machine->bias_level = level;
+ }
return 0;
}
@@ -1082,8 +1091,10 @@ static int tegra30_soc_set_bias_level_post(struct snd_soc_card *card,
struct tegra_max98088 *machine = snd_soc_card_get_drvdata(card);
if (machine->bias_level != SND_SOC_BIAS_OFF &&
- level == SND_SOC_BIAS_OFF)
+ level == SND_SOC_BIAS_OFF && (machine->clock_enabled)) {
+ machine->clock_enabled = 0;
tegra_asoc_utils_clk_disable(&machine->util_data);
+ }
machine->bias_level = level;
@@ -1156,6 +1167,7 @@ static __devinit int tegra_max98088_driver_probe(struct platform_device *pdev)
tegra_max98088_i2s_dai_name[machine->codec_info[BT_SCO].i2s_id];
#endif
+ card->dapm.idle_bias_off = 1;
ret = snd_soc_register_card(card);
if (ret) {
dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
diff --git a/sound/soc/tegra/tegra_max98095.c b/sound/soc/tegra/tegra_max98095.c
index 95295ef4151e..d065b78164ac 100644
--- a/sound/soc/tegra/tegra_max98095.c
+++ b/sound/soc/tegra/tegra_max98095.c
@@ -542,6 +542,10 @@ static int tegra_max98095_init(struct snd_soc_pcm_runtime *rtd)
tegra_max98095_hp_jack_pins);
#endif
+ ret = tegra_asoc_utils_register_ctls(&machine->util_data);
+ if (ret < 0)
+ return ret;
+
/* max98095_headset_detect(codec, &tegra_max98095_hp_jack,
SND_JACK_HEADSET); */
@@ -577,6 +581,7 @@ static struct snd_soc_dai_link tegra_max98095_dai[] = {
};
static int tegra30_soc_set_bias_level(struct snd_soc_card *card,
+ struct snd_soc_dapm_context *dapm,
enum snd_soc_bias_level level)
{
struct tegra_max98095 *machine = snd_soc_card_get_drvdata(card);
@@ -591,6 +596,7 @@ static int tegra30_soc_set_bias_level(struct snd_soc_card *card,
}
static int tegra30_soc_set_bias_level_post(struct snd_soc_card *card,
+ struct snd_soc_dapm_context *dapm,
enum snd_soc_bias_level level)
{
struct tegra_max98095 *machine = snd_soc_card_get_drvdata(card);
@@ -654,13 +660,22 @@ static __devinit int tegra_max98095_driver_probe(struct platform_device *pdev)
goto err_switch_unregister;
}
+ if (!card->instantiated) {
+ ret = -ENODEV;
+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+ ret);
+ goto err_unregister_card;
+ }
+
return 0;
+err_unregister_card:
+ snd_soc_unregister_card(card);
err_switch_unregister:
#ifdef CONFIG_SWITCH
switch_dev_unregister(&wired_switch_dev);
-#endif
err_fini_utils:
+#endif
tegra_asoc_utils_fini(&machine->util_data);
err_free_machine:
kfree(machine);
diff --git a/sound/soc/tegra/tegra_p1852.c b/sound/soc/tegra/tegra_p1852.c
index 9506a1c842df..199bb8046636 100644
--- a/sound/soc/tegra/tegra_p1852.c
+++ b/sound/soc/tegra/tegra_p1852.c
@@ -49,7 +49,8 @@ struct tegra_p1852 {
};
static int tegra_p1852_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
+ struct snd_pcm_hw_params *params,
+ int codec_id)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
@@ -61,7 +62,6 @@ static int tegra_p1852_hw_params(struct snd_pcm_substream *substream,
int i2s_daifmt = 0;
int err;
struct tegra_p1852_platform_data *pdata;
- int codec_id = codec_dai->id;
pdata = machine->pdata;
@@ -120,15 +120,39 @@ static int tegra_p1852_hw_params(struct snd_pcm_substream *substream,
dev_err(card->dev, "cpu_dai fmt not set\n");
return err;
}
-
err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
SND_SOC_CLOCK_IN);
if (err < 0)
dev_info(card->dev, "codec_dai clock not set\n");
+ if (pdata->codec_info[codec_id].i2s_format ==
+ format_tdm) {
+ err = snd_soc_dai_set_tdm_slot(cpu_dai,
+ pdata->codec_info[codec_id].rx_mask,
+ pdata->codec_info[codec_id].tx_mask,
+ pdata->codec_info[codec_id].num_slots,
+ pdata->codec_info[codec_id].slot_width);
+ if (err < 0)
+ dev_err(card->dev, "cpu_dai tdm mode setting not done\n");
+ }
+
return 0;
}
+static int tegra_p1852_hw_params_controller1(
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ return tegra_p1852_hw_params(substream, params, 0);
+}
+
+static int tegra_p1852_hw_params_controller2(
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ return tegra_p1852_hw_params(substream, params, 1);
+}
+
static int tegra_hw_free(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -139,8 +163,12 @@ static int tegra_hw_free(struct snd_pcm_substream *substream)
return 0;
}
-static struct snd_soc_ops tegra_p1852_ops = {
- .hw_params = tegra_p1852_hw_params,
+static struct snd_soc_ops tegra_p1852_ops_controller1 = {
+ .hw_params = tegra_p1852_hw_params_controller1,
+ .hw_free = tegra_hw_free,
+};
+static struct snd_soc_ops tegra_p1852_ops_controller2 = {
+ .hw_params = tegra_p1852_hw_params_controller2,
.hw_free = tegra_hw_free,
};
@@ -149,13 +177,13 @@ static struct snd_soc_dai_link tegra_p1852_dai_link[] = {
.name = "I2S-TDM-1",
.stream_name = "TEGRA PCM",
.platform_name = "tegra-pcm-audio",
- .ops = &tegra_p1852_ops,
+ .ops = &tegra_p1852_ops_controller1,
},
{
.name = "I2S-TDM-2",
.stream_name = "TEGRA PCM",
.platform_name = "tegra-pcm-audio",
- .ops = &tegra_p1852_ops,
+ .ops = &tegra_p1852_ops_controller2,
}
};
@@ -199,6 +227,9 @@ static __devinit int tegra_p1852_driver_probe(struct platform_device *pdev)
pdata->codec_info[i].codec_dai_name;
tegra_p1852_dai_link[i].name =
pdata->codec_info[i].name;
+ if (pdata->codec_info[i].pcm_driver)
+ tegra_p1852_dai_link[i].platform_name =
+ pdata->codec_info[i].pcm_driver;
}
ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev, card);
diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c
index 5f2553b3dd66..090e8481dc37 100644
--- a/sound/soc/tegra/tegra_pcm.c
+++ b/sound/soc/tegra/tegra_pcm.c
@@ -58,8 +58,8 @@ static const struct snd_pcm_hardware tegra_pcm_hardware = {
.channels_min = 1,
.channels_max = 2,
.period_bytes_min = 128,
- .period_bytes_max = PAGE_SIZE,
- .periods_min = 2,
+ .period_bytes_max = PAGE_SIZE * 2,
+ .periods_min = 1,
.periods_max = 8,
.buffer_bytes_max = PAGE_SIZE * 8,
.fifo_size = 4,
@@ -281,15 +281,30 @@ int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct tegra_runtime_data *prtd = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct tegra_pcm_dma_params * dmap;
unsigned long flags;
int i;
+ dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+ if (!dmap)
+ return 0;
+
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
prtd->dma_pos = 0;
prtd->dma_pos_end = frames_to_bytes(runtime, runtime->periods * runtime->period_size);
prtd->period_index = 0;
prtd->dma_req_idx = 0;
+ if (prtd->disable_intr) {
+ prtd->dma_req_count = 1;
+ prtd->dma_req[0].complete = NULL;
+ } else if (!prtd->dma_req[0].complete) {
+ prtd->dma_req[0].complete = dma_complete_callback;
+ prtd->dma_req_count =
+ (MAX_DMA_REQ_COUNT <= runtime->periods) ?
+ MAX_DMA_REQ_COUNT : runtime->periods;
+ }
/* Fall-through */
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
@@ -307,8 +322,9 @@ int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
spin_unlock_irqrestore(&prtd->lock, flags);
tegra_dma_cancel(prtd->dma_chan);
for (i = 0; i < prtd->dma_req_count; i++) {
- if (prtd->dma_req[i].status ==
- -TEGRA_DMA_REQ_ERROR_ABORTED)
+ if (prtd->dma_req[i].complete &&
+ (prtd->dma_req[i].status ==
+ -TEGRA_DMA_REQ_ERROR_ABORTED))
prtd->dma_req[i].complete(&prtd->dma_req[i]);
}
break;
@@ -443,7 +459,7 @@ void tegra_pcm_free(struct snd_pcm *pcm)
static int tegra_pcm_probe(struct snd_soc_platform *platform)
{
- if(machine_is_kai())
+ if(machine_is_kai() || machine_is_tegra_enterprise())
platform->dapm.idle_bias_off = 1;
return 0;
diff --git a/sound/soc/tegra/tegra_pcm.h b/sound/soc/tegra/tegra_pcm.h
index 7fe22788004b..b63de32023e8 100644
--- a/sound/soc/tegra/tegra_pcm.h
+++ b/sound/soc/tegra/tegra_pcm.h
@@ -53,6 +53,7 @@ struct tegra_runtime_data {
struct tegra_dma_req dma_req[MAX_DMA_REQ_COUNT];
struct tegra_dma_channel *dma_chan;
int dma_req_count;
+ int disable_intr;
};
int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd);
diff --git a/sound/soc/tegra/tegra_rt5640.c b/sound/soc/tegra/tegra_rt5640.c
index 231b0ee61308..765eb59fabae 100644
--- a/sound/soc/tegra/tegra_rt5640.c
+++ b/sound/soc/tegra/tegra_rt5640.c
@@ -547,6 +547,11 @@ static int tegra_rt5640_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_add_routes(dapm, cardhu_audio_map,
ARRAY_SIZE(cardhu_audio_map));
+
+ ret = tegra_asoc_utils_register_ctls(&machine->util_data);
+ if (ret < 0)
+ return ret;
+
/* FIXME: Calculate automatically based on DAPM routes? */
snd_soc_dapm_nc_pin(dapm, "LOUTL");
snd_soc_dapm_nc_pin(dapm, "LOUTR");
diff --git a/sound/soc/tegra/tegra_wm8753.c b/sound/soc/tegra/tegra_wm8753.c
index 795356875ba4..f7c7a4c6b5a1 100644
--- a/sound/soc/tegra/tegra_wm8753.c
+++ b/sound/soc/tegra/tegra_wm8753.c
@@ -379,7 +379,6 @@ static int tegra_bt_call_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_card *card = codec->card;
struct tegra_wm8753 *machine = snd_soc_card_get_drvdata(card);
@@ -783,6 +782,10 @@ static int tegra_wm8753_init(struct snd_soc_pcm_runtime *rtd)
if (ret < 0)
return ret;
+ ret = tegra_asoc_utils_register_ctls(&machine->util_data);
+ if (ret < 0)
+ return ret;
+
snd_soc_dapm_nc_pin(dapm, "ACIN");
snd_soc_dapm_nc_pin(dapm, "ACOP");
snd_soc_dapm_nc_pin(dapm, "OUT3");
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c
index ce608b007bef..063aefe50507 100644
--- a/sound/soc/tegra/tegra_wm8903.c
+++ b/sound/soc/tegra/tegra_wm8903.c
@@ -660,6 +660,10 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
wm8903_mic_detect(codec, &tegra_wm8903_mic_jack, SND_JACK_MICROPHONE,
machine_is_cardhu() ? SND_JACK_MICROPHONE : 0);
+ ret = tegra_asoc_utils_register_ctls(&machine->util_data);
+ if (ret < 0)
+ return ret;
+
snd_soc_dapm_force_enable_pin(dapm, "Mic Bias");
/* FIXME: Calculate automatically based on DAPM routes? */
@@ -898,8 +902,8 @@ err_unregister_card:
err_unregister_switch:
#ifdef CONFIG_SWITCH
switch_dev_unregister(&tegra_wm8903_headset_switch);
-#endif
err_fini_utils:
+#endif
tegra_asoc_utils_fini(&machine->util_data);
err_free_machine:
kfree(machine);